def restart(self, EpsilonNet=None, DiffeonEpsForNet=None, DiffeonSegmentationRatio=None, DecimationTarget=None):
        if EpsilonNet==None:
            if DecimationTarget==None:
                if DiffeonEpsForNet==None:
                    if DiffeonSegmentationRatio==None:
                        c0 = np.copy(self.x0) ;
                        S0 = np.zeros([self.x0.shape[0], self.x0.shape[1], self.x0.shape[1]])
                        #net = range(c0.shape[0])
                        idx = range(c0.shape[0])
                    else:
                        (c0, S0, idx) = gd.generateDiffeonsFromSegmentation(self.fv0, DiffeonSegmentationRatio)
                        #self.S0 *= self.param.sigmaKernel**2;
                else:
                    (c0, S0, idx) = gd.generateDiffeonsFromNet(self.fv0, DiffeonEpsForNet)
            else:
                (c0, S0, idx) = gd.generateDiffeonsFromDecimation(self.fv0, DecimationTarget)
        else:
            net = EspilonNet[2] 
            (c0, S0, idx) = gd.generateDiffeons(self.fv0, EpsilonNet[0], EpsilonNet[1])

        (ctPrev, StPrev, ct, St) = evol.gaussianDiffeonsEvolutionEuler(self.c0, self.S0, self.at, self.param.sigmaKernel, withDiffeonSet=(c0, S0))
        at = np.zeros([self.Tsize, c0.shape[0], self.x0.shape[1]])
        #fvDef = surfaces.Surface(surf=self.fvDef)
        for t in range(self.Tsize):
            g1 = gd.computeProducts(np.squeeze(ct[t,:,:]),np.squeeze(St[t,:,:]), self.param.sigmaKernel) 
            g2 = gd.computeProductsAsym(np.squeeze(ct[t,:,:]),np.squeeze(St[t,:,:]), np.squeeze(ctPrev[t,:,:]),np.squeeze(StPrev[t,:,:]), self.param.sigmaKernel)
            g2a = np.dot(g2, np.squeeze(self.at[t, :, :]))
            at[t, :, :] = LA.solve(g1, g2a)
            g0 = gd.computeProducts(np.squeeze(ctPrev[t,:,:]),np.squeeze(StPrev[t,:,:]), self.param.sigmaKernel)
            n0 = np.multiply(self.at[t, :, :], np.dot(g0, self.at[t, :, :])).sum()
            n1 = np.multiply(at[t, :, :], np.dot(g1, at[t, :, :])).sum()
            print 'norms: ', n0, n1
            # fvDef.updateVertices(np.squeeze(self.xt[t, :, :]))
            # (AV, AF) = fvDef.computeVertexArea()
            # weights = np.zeros([c0.shape[0], self.c0.shape[0]])
            # diffArea = np.zeros(self.c0.shape[0])
            # diffArea2 = np.zeros(c0.shape[0])
            # for k in range(self.npt):
            #     diffArea[self.idx[k]] += AV[k] 
            #     diffArea2[idx[k]] += AV[k]
            #     weights[idx[k], self.idx[k]] += AV[k]
            # weights /= diffArea.reshape([1, self.c0.shape[0]])
            # at[t] = np.dot(weights, self.at[t, :, :])
        self.c0 = c0
        self.idx = idx
        self.S0 = S0
        self.at = at
        self.ndf = self.c0.shape[0]
        self.ct = np.tile(self.c0, [self.Tsize+1, 1, 1])
        self.St = np.tile(self.S0, [self.Tsize+1, 1, 1, 1])
        if self.dcurr:
	    self.b0 = gd.approximateSurfaceCurrent(self.c0, self.S0, self.fv0, self.param.KparDist.sigma)
            #print self.b0.shape
            self.bt = np.tile(self.b0, [self.Tsize+1, 1, 1])
        self.obj = None
        self.objTry = None
        self.gradCoeff = self.ndf
        self.optimizeMatching()
    def __init__(self, Template=None, Target=None, Diffeons=None, EpsilonNet=None, DecimationTarget=None,
                 subsampleTargetSize = -1, 
                 DiffeonEpsForNet=None, DiffeonSegmentationRatio=None, zeroVar=False, fileTempl=None,
                 fileTarg=None, param=None, maxIter=1000, regWeight = 1.0, affineWeight = 1.0, verb=True,
                 rotWeight = None, scaleWeight = None, transWeight = None, testGradient=False, saveFile = 'evolution', affine = 'none', 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 Target==None:
            if fileTarg==None:
                print 'Please provide a target surface'
                return
            else:
                self.fv1 = surfaces.Surface(filename=fileTarg)
        else:
            self.fv1 = surfaces.Surface(surf=Target)

        self.fv0Fine = surfaces.Surface(surf=self.fv0)
        self.saveRate = 10
        self.iter = 0
        self.gradEps = -1
        self.npt = self.fv0.vertices.shape[0]
        self.dim = self.fv0.vertices.shape[1]
        self.setOutputDir(outputDir)
        self.maxIter = maxIter
        self.verb = verb
        self.testGradient = testGradient
        self.regweight = regWeight
        self.affine = affine
        affB = AffineBasis(self.dim, affine)
        self.affineDim = affB.affineDim
        self.affineBasis = affB.basis
        self.affineWeight = affineWeight * np.ones([self.affineDim, 1])
        if (len(affB.rotComp) > 0) & (rotWeight != None):
            self.affineWeight[affB.rotComp] = rotWeight
        if (len(affB.simComp) > 0) & (scaleWeight != None):
            self.affineWeight[affB.simComp] = scaleWeight
        if (len(affB.transComp) > 0) & (transWeight != None):
            self.affineWeight[affB.transComp] = transWeight

        if param==None:
            self.param = SurfaceMatchingParam()
        else:
            self.param = param
        self.x0 = self.fv0.vertices
        if Diffeons==None:
            if EpsilonNet==None:
                if DecimationTarget==None:
                    if DiffeonEpsForNet==None:
                        if DiffeonSegmentationRatio==None:
                            self.c0 = np.copy(self.x0) ;
                            self.S0 = np.zeros([self.x0.shape[0], self.x0.shape[1], self.x0.shape[1]])
                            self.idx = None
                        else:
                            (self.c0, self.S0, self.idx) = gd.generateDiffeonsFromSegmentation(self.fv0, DiffeonSegmentationRatio)
                            #self.S0 *= self.param.sigmaKernel**2;
                    else:
                        (self.c0, self.S0, self.idx) = gd.generateDiffeonsFromNet(self.fv0, DiffeonEpsForNet)
                else:
                    (self.c0, self.S0, self.idx) = gd.generateDiffeonsFromDecimation(self.fv0, DecimationTarget)
            else:
                (self.c0, self.S0, self.idx) = gd.generateDiffeons(self.fv0, EpsilonNet[0], EpsilonNet[1])
        else:
            (self.c0, self.S0, self.idx) = Diffeons
        if zeroVar:
	    self.S0 = np.zeros(self.S0.shape)

            #print self.S0
        if (subsampleTargetSize > 0):
            self.fv0.Simplify(subsampleTargetSize)
            v0 = self.fv0.surfVolume()
            v1 = self.fv0Fine.surfVolume()
            if (v0*v1 < 0):
                self.fv0.flipFaces()
            if self.param.errorType == 'diffeonCurrent':
                n = self.fv0Fine.vertices.shape[0]
                m = self.fv0.vertices.shape[0]
                dist2 = ((self.fv0Fine.vertices.reshape([n, 1, 3]) -
                          self.fv0.vertices.reshape([1,m,3]))**2).sum(axis=2)
                idx = - np.ones(n, dtype=np.int)
                for p in range(n):
                    closest = np.unravel_index(np.argmin(dist2[p, :].ravel()), [m, 1])
                    idx[p] = closest[0]
                (x0, xS0, idx) = gd.generateDiffeons(self.fv0Fine, self.fv0.vertices, idx)
                b0 = gd.approximateSurfaceCurrent(x0, xS0, self.fv0Fine, self.param.KparDist.sigma)
                gdOpt = gd.gdOptimizer(surf=self.fv0Fine, sigmaDist = self.param.KparDist.sigma, Diffeons = (x0, xS0, b0) , testGradient=False, maxIter=50)
                gdOpt.optimize()
                self.x0 = gdOpt.c0
                self.xS0 = gdOpt.S0
                self.b0 = gdOpt.b0
            else:
                self.x0 = self.fv0.vertices
            print 'simplified template', self.fv0.vertices.shape[0]
        self.fvDef = surfaces.Surface(surf=self.fv0)
        self.ndf = self.c0.shape[0]
        self.Tsize = int(round(1.0/self.param.timeStep))
        self.at = np.zeros([self.Tsize, self.c0.shape[0], self.x0.shape[1]])
        self.atTry = np.zeros([self.Tsize, self.c0.shape[0], self.x0.shape[1]])
        self.Afft = np.zeros([self.Tsize, self.affineDim])
        self.AfftTry = np.zeros([self.Tsize, self.affineDim])
        self.xt = np.tile(self.x0, [self.Tsize+1, 1, 1])
        self.ct = np.tile(self.c0, [self.Tsize+1, 1, 1])
        self.St = np.tile(self.S0, [self.Tsize+1, 1, 1, 1])
        print 'error type:', self.param.errorType
	if self.param.errorType =='diffeonCurrent':
	    self.xSt = np.tile(self.xS0, [self.Tsize+1, 1, 1, 1])
	    self.bt = np.tile(self.b0, [self.Tsize+1, 1, 1])
	    self.dcurr = True
	else:
	    self.dcurr=False
        self.obj = None
        self.objTry = None
        self.gradCoeff = self.ndf
        self.saveFile = saveFile
        self.fv0.saveVTK(self.outputDir+'/Template.vtk')
        self.fv1.saveVTK(self.outputDir+'/Target.vtk')