def  objectiveFunDef(self, a0, rhot, Afft, withTrajectory = False, withJacobian=False, Init = None, display=False):
     if Init == None:
         x0 = self.x0
     else:
         x0 = Init[0]
         
     param = self.param
     timeStep = 1.0/self.Tsize
     dim2 = self.dim**2
     A = [np.zeros([self.Tsize, self.dim, self.dim]), np.zeros([self.Tsize, self.dim])]
     if self.affineDim > 0:
         for t in range(self.Tsize):
             AB = np.dot(self.affineBasis, Afft[t])
             A[0][t] = AB[0:dim2].reshape([self.dim, self.dim])
             A[1][t] = AB[dim2:dim2+self.dim]
     #print a0.shape
     if withJacobian:
         (xt, at, Jt)  = evol.secondOrderEvolution(x0, a0, rhot, param.KparDiff, withJacobian=True,affine=A)
     else:
         (xt, at)  = evol.secondOrderEvolution(x0, a0, rhot, param.KparDiff, affine=A)
     #print xt[-1, :, :]
     #print obj
     obj0 = 0.5 * (a0 * param.KparDiff.applyK(x0,a0)).sum()
     obj1 = 0
     obj2 =0
     for t in range(self.Tsize):
         rho = np.squeeze(rhot[t, :, :])            
         obj1 += timeStep* self.controlWeight * (rho**2).sum()/2
         if self.affineDim > 0:
             obj2 +=  timeStep * (self.affineWeight.reshape(Afft[t].shape) * Afft[t]**2).sum()/2
         #print xt.sum(), at.sum(), obj
     obj = obj1+obj2+obj0
     if display:
         logging.info('deformation terms: init %f, rho %f, aff %f'%(obj0,obj1,obj2))
     if withJacobian:
         return obj, xt, at, Jt
     elif withTrajectory:
         return obj, xt, at
     else:
         return obj
    def __init__(self, Template=None, Targets=None, fileTempl=None, fileTarg=None, param=None, initialMomentum=None,
                 maxIter=1000, regWeight = 1.0, verb=True, typeRegression='spline2', affine = 'none', controlWeight = 1.0,
                 affineWeight = 1.0, rotWeight = None, scaleWeight = None, transWeight = None,
                 subsampleTargetSize=-1, testGradient=True, saveFile = 'evolution', outputDir = '.'):
        if Template==None:
            if fileTempl==None:
                print 'Please provide a template surface'
                return
            else:
                self.fv0 = surfaces.Surface(filename=fileTempl)
        else:
            self.fv0 = surfaces.Surface(surf=Template)
        if Targets==None:
            if fileTarg==None:
                print 'Please provide a list of target surfaces'
                return
            else:
                self.fv1 = [] ;
                for f in fileTarg:
                    self.fv1.append(surfaces.Surface(filename=f))
        else:
            self.fv1 = [] ;
            for s in Targets:
                self.fv1.append(surfaces.Surface(surf=s))


        self.nTarg = len(self.fv1)
        self.saveRate = 10
        self.iter = 0
        self.outputDir = outputDir
        if not os.access(outputDir, os.W_OK):
            if os.access(outputDir, os.F_OK):
                print 'Cannot save in ' + outputDir
                return
            else:
                os.mkdir(outputDir)
        self.dim = self.fv0.vertices.shape[1]
        self.maxIter = maxIter
        self.verb = verb
        self.testGradient = testGradient
        self.regweight = regWeight
        self.affine = affine
        if self.affine=='euclidean' or self.affine=='translation':
            self.saveCorrected = True
        else:
            self.saveCorrected = False

        self.affB = AffineBasis(self.dim, affine)
        self.affineDim = self.affB.affineDim
        self.affineBasis = self.affB.basis
        self.affineWeight = affineWeight * np.ones(self.affineDim)
        if (len(self.affB.rotComp) > 0) & (rotWeight != None):
            self.affineWeight[self.affB.rotComp] = rotWeight
        if (len(self.affB.simComp) > 0) & (scaleWeight != None):
            self.affineWeight[self.affB.simComp] = scaleWeight
        if (len(self.affB.transComp) > 0) & (transWeight != None):
            self.affineWeight[self.affB.transComp] = transWeight
        self.affw = affineWeight

        self.controlWeight = controlWeight
        self.typeRegression = 'affine' 
        self.typeRegressionSave = typeRegression 

        if param==None:
            self.param = SurfaceMatchingParam()
        else:
            self.param = param

        self.fv0Fine = surfaces.Surface(surf=self.fv0)
        if (subsampleTargetSize > 0):
            self.fv0.Simplify(subsampleTargetSize)
            v0 = self.fv0.surfVolume()
            for s in self.fv1:
                v1 = s.surfVolume()
                if (v0*v1 < 0):
                    s.flipFaces()
            print 'simplified template', self.fv0.vertices.shape[0]
        self.x0 = self.fv0.vertices
        self.fvDef = []
        for k in range(self.nTarg):
            self.fvDef.append(surfaces.Surface(surf=self.fv0))
        self.npt = self.x0.shape[0]
        self.Tsize1 = int(round(1.0/self.param.timeStep))
        self.Tsize = self.nTarg*self.Tsize1
        self.rhot = np.zeros([self.Tsize, self.x0.shape[0], self.x0.shape[1]])
        if initialMomentum==None:
            self.xt = np.tile(self.x0, [self.Tsize+1, 1, 1])
            self.a0 = np.zeros([self.x0.shape[0], self.x0.shape[1]])
            self.at = np.tile(self.a0, [self.Tsize+1, 1, 1])
        else:
            self.a0 = initialMomentum
            (self.xt, self.at)  = evol.secondOrderEvolution(self.x0, self.a0, self.rhot, self.param.KparDiff)

        self.v = np.zeros([self.Tsize+1, self.npt, self.dim])
        self.rhotTry = np.zeros([self.Tsize, self.x0.shape[0], self.x0.shape[1]])
        self.a0Try = np.zeros([self.x0.shape[0], self.x0.shape[1]])
        self.Afft = np.zeros([self.Tsize, self.affineDim])
        self.AfftTry = np.zeros([self.Tsize, self.affineDim])

        self.obj = None
        self.objTry = None
        self.gradCoeff = self.fv0.vertices.shape[0]
        self.saveFile = saveFile
        self.fv0.saveVTK(self.outputDir+'/Template.vtk')
        for k,s in enumerate(self.fv1):
            s.saveVTK(self.outputDir+'/Target'+str(k)+'.vtk')
        self.affBurnIn = 50
        self.coeffAff1 = 1
        self.coeffAff2 = 10.
        self.coeffAff = self.coeffAff1
        z= self.fv0.surfVolume()
        if (z < 0):
            self.fv0ori = -1
        else:
            self.fv0ori = 1
    def endOfIteration(self):
        self.iter += 1
        if self.iter >= self.affBurnIn:
            self.typeRegression = self.typeRegressionSave
            self.affine = 'none'
            #self.coeffAff = self.coeffAff2
        if (self.iter % self.saveRate == 0):
            logging.info('Saving surfaces...')
            (obj1, self.xt, self.at) = self.objectiveFunDef(self.a0, self.rhot, self.Afft, withTrajectory=True, display=True)
            for k in range(self.nTarg):
                self.fvDef[k].updateVertices(np.squeeze(self.xt[(k+1)*self.Tsize1, :, :]))
            dim2 = self.dim**2
            A = [np.zeros([self.Tsize, self.dim, self.dim]), np.zeros([self.Tsize, self.dim])]
            if self.affineDim > 0:
                for t in range(self.Tsize):
                    AB = np.dot(self.affineBasis, self.Afft[t])
                    A[0][t] = AB[0:dim2].reshape([self.dim, self.dim])
                    A[1][t] = AB[dim2:dim2+self.dim]
                    
            (xt, at, ft, Jt)  = evol.secondOrderEvolution(self.x0, self.a0,  self.rhot, self.param.KparDiff, affine=A,
                                                           withPointSet = self.fv0Fine.vertices, withJacobian=True)

            if self.saveCorrected:
                f = surfaces.Surface(surf=self.fv0Fine)
                X = self.affB.integrateFlow(self.Afft)
                displ = np.zeros(self.x0.shape[0])
                dt = 1.0 /self.Tsize ;
                atCorr = np.zeros(at.shape) 
                for t in range(self.Tsize+1):
                    U = la.inv(X[0][t,...])
                    yyt = np.dot(self.xt[t,...] - X[1][t, ...], U.T)
                    zt = np.dot(xt[t,...] - X[1][t, ...], U.T)
                    if t < self.Tsize:
                        a = np.dot(self.at[t,...], X[0][t,...])
                        atCorr[t,...] = a
                        vt = self.param.KparDiff.applyK(yyt, a, firstVar=zt)
                        vt = np.dot(vt, U.T)
                    f.updateVertices(zt)
                    vf = surfaces.vtkFields() ;
                    vf.scalars.append('Jacobian') ;
                    vf.scalars.append(np.exp(Jt[t, :])-1)
                    vf.scalars.append('displacement')
                    vf.scalars.append(displ)
                    vf.vectors.append('velocity') ;
                    vf.vectors.append(vt)
                    nu = self.fv0ori*f.computeVertexNormals()
                    displ += dt * (vt*nu).sum(axis=1)
                    f.saveVTK2(self.outputDir +'/'+self.saveFile+'Corrected'+str(t)+'.vtk', vf)
                (foo,zt) = evol.landmarkDirectEvolutionEuler(self.x0, atCorr, self.param.KparDiff, withPointSet = self.fv0Fine.vertices)
                for t in range(self.Tsize+1):
                    f.updateVertices(zt[t,...])
                    f.saveVTK(self.outputDir +'/'+self.saveFile+'CorrectedCheck'+str(t)+'.vtk')
                (foo,foo2,zt) = evol.secondOrderEvolution(self.x0, atCorr[0,...], self.rhot, self.param.KparDiff, withPointSet = self.fv0Fine.vertices)
                for t in range(self.Tsize+1):
                    f.updateVertices(zt[t,...])
                    f.saveVTK(self.outputDir +'/'+self.saveFile+'CorrectedCheckBis'+str(t)+'.vtk')
                 

                for k,fv in enumerate(self.fv1):
                    f = surfaces.Surface(surf=fv)
                    U = la.inv(X[0][(k+1)*self.Tsize1])
                    yyt = np.dot(f.vertices - X[1][(k+1)*self.Tsize1, ...], U.T)
                    f.updateVertices(yyt)
                    f.saveVTK(self.outputDir +'/Target'+str(k)+'Corrected.vtk')
            
            fvDef = surfaces.Surface(surf=self.fv0Fine)
            AV0 = fvDef.computeVertexArea()
            nu = self.fv0ori*self.fv0Fine.computeVertexNormals()
            #v = self.v[0,...]
            displ = np.zeros(self.npt)
            dt = 1.0 /self.Tsize ;
            v = self.param.KparDiff.applyK(ft[0,...], self.at[0,...], firstVar=self.xt[0,...])
            for kk in range(self.Tsize+1):
                fvDef.updateVertices(np.squeeze(ft[kk, :, :]))
                AV = fvDef.computeVertexArea()
                AV = (AV[0]/AV0[0])-1
                vf = surfaces.vtkFields() ;
                vf.scalars.append('Jacobian') ;
                vf.scalars.append(np.exp(Jt[kk, :])-1)
                vf.scalars.append('Jacobian_T') ;
                vf.scalars.append(AV[:,0])
                vf.scalars.append('Jacobian_N') ;
                vf.scalars.append(np.exp(Jt[kk, :])/(AV[:,0]+1)-1)
                vf.scalars.append('displacement')
                vf.scalars.append(displ)
                displ += dt * (v*nu).sum(axis=1)
                if kk < self.Tsize:
                    nu = self.fv0ori*fvDef.computeVertexNormals()
                    v = self.param.KparDiff.applyK(ft[kk,...], self.at[kk,...], firstVar=self.xt[kk,...])
                    #v = self.v[kk,...]
                    kkm = kk
                else:
                    kkm = kk-1
                vf.vectors.append('velocity') ;
                vf.vectors.append(self.v[kkm,:])
                fvDef.saveVTK2(self.outputDir +'/'+ self.saveFile+str(kk)+'.vtk', vf)
        else:
            (obj1, self.xt, self.at) = self.objectiveFunDef(self.a0, self.rhot, self.Afft, withTrajectory=True, display=True)
            for k in range(self.nTarg):
                self.fvDef[k].updateVertices(np.squeeze(self.xt[(k+1)*self.Tsize1, :, :]))