def _assemble(self): # Get input: self.gamma = self.Parameters['gamma'] if self.Parameters.has_key('beta'): self.beta = self.Parameters['beta'] else: self.beta = 0.0 self.Vm = self.Parameters['Vm'] self.m0 = Function(self.Vm) if self.Parameters.has_key('m0'): setfct(self.m0, self.Parameters['m0']) self.mtrial = TrialFunction(self.Vm) self.mtest = TestFunction(self.Vm) self.mysample = Function(self.Vm) self.draw = Function(self.Vm) # Assemble: self.R = assemble(inner(nabla_grad(self.mtrial), \ nabla_grad(self.mtest))*dx) self.M = assemble(inner(self.mtrial, self.mtest) * dx) self.Msolver = PETScKrylovSolver('cg', 'jacobi') self.Msolver.parameters["maximum_iterations"] = 2000 self.Msolver.parameters["relative_tolerance"] = 1e-24 self.Msolver.parameters["absolute_tolerance"] = 1e-24 self.Msolver.parameters["error_on_nonconvergence"] = True self.Msolver.parameters["nonzero_initial_guess"] = False self.Msolver.set_operator(self.M) # preconditioner is Gamma^{-1}: if self.beta > 1e-10: self.precond = self.gamma * self.R + self.beta * self.M else: self.precond = self.gamma * self.R + (1e-10) * self.M # Minvprior is M.A^2 (if you use M inner-product): self.Minvprior = self.gamma * self.R + self.beta * self.M
def linesearch(self): """ Perform inexact backtracking line search """ regularization = self.parameters["regularization"] # compute new direction for dual variables if regularization == "TV" and self.Reg.isPD(): self.Reg.compute_dw(self.dg) # line search for primal variable self.alpha = self.parameters["alpha0"] rho = self.parameters["rho"] c = self.parameters["c"] self.computecost() costref = self.cost cdJdf = ((self.MG).inner(self.dg.vector())) * c self.LS = False for ii in xrange(self.parameters["max_backtrack"]): setfct(self.gtmp, self.g.vector() + self.dg.vector() * self.alpha) if self.computecost(self.gtmp) < costref + self.alpha * cdJdf: self.g.vector().axpy(self.alpha, self.dg.vector()) self.LS = True break else: self.alpha *= rho # update dual variable if regularization == "TV" and self.Reg.isPD(): self.Reg.update_w(self.alpha)
def assemble_hessian(self, m): """ build Hessian matrix at given point m """ setfct(self.m, m) self._assemble_invMw() self.Ax = assemble(self.wkformAx) Hxasym = MatMatMult(self.Htvx, MatMatMult(self.invMwMat, self.Ax)) Hx = (Hxasym + Transpose(Hxasym)) * 0.5 Axrs = assemble(self.wkformAxrs) Hxrsasym = MatMatMult(self.Htvx, MatMatMult(self.invMwMat, Axrs)) Hxrs = (Hxrsasym + Transpose(Hxrsasym)) * 0.5 self.Ay = assemble(self.wkformAy) Hyasym = MatMatMult(self.Htvy, MatMatMult(self.invMwMat, self.Ay)) Hy = (Hyasym + Transpose(Hyasym)) * 0.5 Ayrs = assemble(self.wkformAyrs) Hyrsasym = MatMatMult(self.Htvy, MatMatMult(self.invMwMat, Ayrs)) Hyrs = (Hyrsasym + Transpose(Hyrsasym)) * 0.5 self.H = Hx + Hy self.Hrs = Hxrs + Hyrs PCGN = self.parameters['PCGN'] if PCGN: HGN = assemble(self.wkformGNhess) self.precond = HGN + self.sMass else: self.precond = self.Hrs + self.sMass
def hessianab(self, m1h, m2h): """ m1h, m2h = Vector(V) """ setfct(self.m1h, m1h) setfct(self.m2h, m2h) assign(self.m12h.sub(0), self.m1h) assign(self.m12h.sub(1), self.m2h) return self.H * self.m12h.vector()
def iteration_centered(self, tt): setfct(self.rhs, (self.Dt**2)*self.ftime(tt)) self.rhs.vector().axpy(-1.0, self.MminD*self.u0.vector()) self.rhs.vector().axpy(2.0, self.M*self.u1.vector()) self.rhs.vector().axpy(-self.Dt**2, self.K*self.u1.vector()) if not self.bc == None: self.bc.apply(self.rhs.vector()) self.solverMplD.solve(self.u2.vector(), self.rhs.vector())
def copy(self): """(hard) copy constructor""" newobj = self.__class__(self.PDE.copy()) setfct(newobj.MG, self.MG) setfct(newobj.srchdir, self.srchdir) newobj.obsop = self.obsop return newobj
def linesearch(self, MG): """ Perform inexact backtracking line search """ alphaLS = self.parametersLS['alpha0'] rhoLS = self.parametersLS['rho'] cLS = self.parametersLS['c'] cost, misfit, reg = self.costmisfitreg() costref = cost setfct(self.ucopy, self.u) MGdu = MG.inner(self.du.vector()) * cLS success = False for ii in xrange(self.parametersLS['max_backtrack']): setfct(self.u, self.ucopy) self.u.vector().axpy(alphaLS, self.du.vector()) cost, misfit, reg = self.costmisfitreg() if cost < costref + alphaLS * MGdu: success = True break else: alphaLS *= rhoLS if self.Regul.isPD(): self.Regul.update_w(self.du.vector(), alphaLS) return success, alphaLS, cost, misfit, reg
def hessianab(self, m1h, m2h): """ m1h, m2h = Vector(V) """ setfct(self.m1, m1h) setfct(self.m2, m2h) assign(self.m.sub(0), self.m1) assign(self.m.sub(1), self.m2) return self.regTV.hessian(self.m.vector())
def hessianab(self, ahat, bhat): """ ahat, bhat = Vector(V) """ setfct(self.ahat, ahat) setfct(self.bhat, bhat) assign(self.abhat.sub(0), self.ahat) assign(self.abhat.sub(1), self.bhat) return self.H * self.abhat.vector()
def assemble_GNhessian(self, m_in): """ Assemble the Gauss-Newton Hessian at m_in Not used anymore (wkformhess selects GN Hessian if needed) Left here for back-compatibility """ setfct(self.m, m_in) self.H = assemble(self.wkformGNhess) self.precond = self.H + self.sMass
def iteration_backward(self, tt): setfct(self.rhs, self.Dt*self.ftime(tt)) self.rhs.vector().axpy(-self.Dt, self.K*self.u1.vector()) self.rhs.vector().axpy(-1.0, self.D*(self.u1.vector()-self.u0.vector())) if not self.bc == None: self.bc.apply(self.rhs.vector()) self.solverM.solve(self.sol.vector(), self.rhs.vector()) setfct(self.u2, 2.0*self.u1.vector()) self.u2.vector().axpy(-1.0, self.u0.vector()) self.u2.vector().axpy(self.Dt, self.sol.vector())
def plot_timeseries(self, timeseries, varname, index, skip, function): """ Plot every 'skip' entry of entry 'index' of a 'timeseries'. 'function' = dl.Function """ self.set_varname(varname) for ii, sol in enumerate(timeseries): if ii % skip == 0: setfct(function, sol[index]) self.plot_vtk(function, ii) self.gather_vtkplots()
def plot_timeseries(self, timeseries, varname, index, skip, function): """ Plot every 'skip' entry of entry 'index' of a 'timeseries'. 'function' = dl.Function """ self.set_varname(varname) for ii, sol in enumerate(timeseries): if ii%skip == 0: setfct(function, sol[index]) self.plot_vtk(function, ii) self.gather_vtkplots()
def assemble_hessian(self, m_in): """ Assemble the Hessian of TV at m_in """ setfct(self.m, m_in) self.H = assemble(self.wkformhess) PCGN = self.parameters['PCGN'] if PCGN: HGN = assemble(self.wkformGNhess) self.precond = HGN + self.sMass else: self.precond = self.H + self.sMass
def solveTV(self): """ Solve image denoising pb """ self.u.vector().zero() normu_true = self.mediummisfit() # initial state = noisy image setfct(self.u, self.u_0) print 'min(u)={}, max(u)={}'.format(\ np.amin(self.u.vector().array()), np.amax(self.u.vector().array())) cost, misfit, reg = self.costmisfitreg() costold = cost MG, normMG = self.gradient() normMG0 = normMG print '\t{:12s} {:12s} {:12s} {:12s} {:12s} {:12s} {:12s}\t{:12s} {:12s}'.format(\ 'iter', 'cost', 'misfit', 'reg', '||G||', 'a_LS', 'medmisfit', 'tol_cg', 'n_cg') print '{:12d} {:12.4e} {:12.4e} {:12.4e} {:12.4e} {:12s} {:12.2e} ({:7.2f} %)'.format(\ 0, cost, misfit, reg, normMG, '', self.mediummisfit(), 100.*self.mediummisfit()/normu_true) cgtol = self.parametersLS['cgtol'] maxiter = self.parametersLS['maxiter'] for ii in xrange(maxiter): if self.inexact: cgtol = min(cgtol, np.sqrt(normMG / normMG0)) #cgtol = min(0.5, np.sqrt(normMG/normMG0))) else: cgtol = 1e-12 cgiter, MGdu = self.searchdirection(MG, cgtol) success, alphaLS, cost, misfit, reg = self.linesearch(MG) MG, normMG = self.gradient() print '{:12d} {:12.4e} {:12.4e} {:12.4e} {:12.4e} {:12.4e} {:12.2e} ({:7.2f} %) {:12.2e} {:12d}'.format(\ ii+1, cost, misfit, reg, normMG, alphaLS, \ self.mediummisfit(), 100.*self.mediummisfit()/normu_true, cgtol, cgiter) if normMG < min(1e-12, 1e-10 * normMG0): print 'gradient sufficiently reduced -- optimization converged' break if not success: print 'Line search failed -- optimization aborted' break if np.abs(cost - costold) / costold < 1e-14: if cgtol < 1e-10: print 'cost functional stagnates -- optimization aborted' break else: cgtol *= 1e-3 costold = cost print 'min(u)={}, max(u)={}'.format(\ np.amin(self.u.vector().array()), np.amax(self.u.vector().array()))
def ftimeincradj(self, tt): """ Compute rhs for incremental adjoint at time tt """ try: indexf = int(np.where(isequal(self.PDE.times, tt, 1e-14))[0]) indexa = int(np.where(isequal(self.PDE.times[::-1], tt, 1e-14))[0]) except: print 'Error in ftimeincradj at time {}'.format(tt) print np.min(np.abs(self.PDE.times-tt)) sys.exit(0) # B* B phat # assert isequal(tt, self.solincrfwd[indexf][1], 1e-16) setfct(self.phat, self.solincrfwd[indexf][0]) self.qhat.vector().zero() self.qhat.vector().axpy(1.0, self.obsop.incradj(self.phat, tt)) if not self.GN: # bhat: bhat*grad(ptilde).grad(v) # assert isequal(tt, self.soladji[indexa][1], 1e-16) setfct(self.q, self.soladji[indexa][0]) self.qhat.vector().axpy(1.0, self.C*self.q.vector()) # ahat: ahat*ptilde*q'': setfct(self.q, self.solppadji[indexa][0]) self.qhat.vector().axpy(1.0, self.get_incra(self.q.vector())) # ABC: if self.PDE.parameters['abc']: setfct(self.phat, self.solpadji[indexa][0]) self.qhat.vector().axpy(-0.5, self.Dp*self.phat.vector()) return -1.0*self.qhat.vector()
def solvefwd(self, cost=False): self.PDE.set_fwd() self.PDE.ftime = self.fwdsource self.solfwd,_ = self.PDE.solve() # observations: self.Bp = np.zeros((len(self.obsop.PtwiseObs.Points),len(self.solfwd))) for index, sol in enumerate(self.solfwd): setfct(self.p, sol[0]) self.Bp[:,index] = self.obsop.obs(self.p) if cost: assert not self.dd == None, "Provide observations" self.misfit = self.obsop.costfct(self.Bp, self.dd, self.PDE.times) self.cost_reg = self.regularization.cost(self.PDE.lam) self.cost = self.misfit + self.alpha_reg*self.cost_reg
def solve(self): """ General solver method """ if self.timestepper == 'backward': def iterate(tt): self.iteration_backward(tt) elif self.timestepper == 'centered': def iterate(tt): self.iteration_centered(tt) else: print "Time stepper not implemented" sys.exit(1) if self.verbose: print 'Compute solution' solout = [] # Store computed solution # u0: tt = self.get_tt(0) if self.verbose: print 'Compute solution -- time {}'.format(tt) setfct(self.u0, self.u0init) solout.append([self.u0.vector().array(), tt]) # Compute u1: if not self.u1init == None: self.u1 = self.u1init else: assert(not self.utinit == None) setfct(self.rhs, self.ftime(tt)) self.rhs.vector().axpy(-self.fwdadj, self.D*self.utinit.vector()) self.rhs.vector().axpy(-1.0, self.K*self.u0.vector()) if not self.bc == None: self.bc.apply(self.rhs.vector()) self.solverM.solve(self.sol.vector(), self.rhs.vector()) setfct(self.u1, self.u0) self.u1.vector().axpy(self.fwdadj*self.Dt, self.utinit.vector()) self.u1.vector().axpy(0.5*self.Dt**2, self.sol.vector()) tt = self.get_tt(1) if self.verbose: print 'Compute solution -- time {}'.format(tt) solout.append([self.u1.vector().array(), tt]) # Iteration for nn in xrange(2, self.Nt+1): iterate(tt) # Advance to next time step setfct(self.u0, self.u1) setfct(self.u1, self.u2) tt = self.get_tt(nn) if self.verbose: print 'Compute solution -- time {}, rhs {}'.\ format(tt, np.max(np.abs(self.ftime(tt)))) solout.append([self.u1.vector().array(),tt]) if self.fwdadj > 0.0: assert isequal(tt, self.Tf, 1e-16), \ 'tt={}, Tf={}, reldiff={}'.format(tt, self.Tf, abs(tt-self.Tf)/self.Tf) else: assert isequal(tt, self.t0, 1e-16), \ 'tt={}, t0={}, reldiff={}'.format(tt, self.t0, abs(tt-self.t0)) return solout, self.computeerror()
def generatedata(self, noisepercent): """ compute data and add noisepercent (%) of noise """ sigma = noisepercent * np.linalg.norm(self.f_true.vector().array()) / np.sqrt(self.dimV) print "sigma_noise = ", sigma np.random.seed(11) # TODO: tmp eta = sigma * np.random.randn(self.dimV) self.dn = dl.Function(self.V) setfct(self.dn, eta) self.dn.vector().axpy(1.0, self.f_true.vector()) print "min(true)={}, max(true)={}".format( np.amin(self.f_true.vector().array()), np.amax(self.f_true.vector().array()) ) print "min(noisy)={}, max(noisy)={}".format( np.amin(self.dn.vector().array()), np.amax(self.dn.vector().array()) )
def grad(self, m): """ compute the gradient at m """ setfct(self.m, m) self._assemble_invMw() self.gwx.vector().zero() self.gwx.vector().axpy(1.0, assemble(self.misfitwx)) normgwx = norm(self.gwx.vector()) self.gwy.vector().zero() self.gwy.vector().axpy(1.0, assemble(self.misfitwy)) normgwy = norm(self.gwy.vector()) if self.parameters['print']: print '[TVPD] |gw|={}'.format(np.sqrt(normgwx**2 + normgwy**2)) return self.Htvx*(self.wx.vector() - self.invMwd*self.gwx.vector()) \ + self.Htvy*(self.wy.vector() - self.invMwd*self.gwy.vector())
def solvefwd(self, cost=False): self.PDE.set_fwd() self.solfwd, self.solpfwd, self.solppfwd = [], [], [] self.Bp = [] #TODO: make fwdsource iterable to return source term Ricker = self.fwdsource[0] srcv = self.fwdsource[2] for sii in self.srcindex: ptsrc = self.fwdsource[1][sii] def srcterm(tt): srcv.zero() srcv.axpy(Ricker(tt), ptsrc) return srcv self.PDE.ftime = srcterm solfwd, solpfwd, solppfwd,_ = self.PDE.solve() self.solfwd.append(solfwd) self.solpfwd.append(solpfwd) self.solppfwd.append(solppfwd) self.PDEcount += 1 #TODO: come back and parallellize this too (over time steps) Bp = np.zeros((len(self.obsop.PtwiseObs.Points),len(solfwd))) for index, sol in enumerate(solfwd): setfct(self.p, sol[0]) Bp[:,index] = self.obsop.obs(self.p) self.Bp.append(Bp) if cost: assert not self.dd == None, "Provide data observations to compute cost" self.cost_misfit_local = 0.0 for Bp, dd in izip(self.Bp, self.dd): self.cost_misfit_local += self.obsop.costfct(\ Bp[:,self.tsteps], dd[:,self.tsteps],\ self.PDE.times[self.tsteps], self.factors[self.tsteps]) self.cost_misfit = MPI.sum(self.mpicomm_global, self.cost_misfit_local) self.cost_misfit /= len(self.fwdsource[1]) self.cost_reg = self.regularization.costab(self.PDE.a, self.PDE.b) self.cost = self.cost_misfit + self.alpha_reg*self.cost_reg if DEBUG: print 'cost_misfit={}, cost_reg={}'.format(\ self.cost_misfit, self.cost_reg)
def test_gradient(self, f=None, n=5): """ test gradient with FD approx around point f """ if f == None: f = self.f_true pm = [1.0, -1.0] eps = 1e-5 self.gradient(f) for nn in xrange(1, n + 1): expr = dl.Expression("sin(n*pi*x[0]/200)*sin(n*pi*x[1]/100)", n=nn) df = dl.interpolate(expr, self.V) MGdf = self.MG.inner(df.vector()) cost = [] for sign in pm: setfct(self.g, f) self.g.vector().axpy(sign * eps, df.vector()) cost.append(self.computecost(self.g)) MGFD = (cost[0] - cost[1]) / (2 * eps) print "n={}:\tMGFD={:.5e}, MGdf={:.5e}, error={:.2e}".format( nn, MGFD, MGdf, np.abs(MGdf - MGFD) / np.abs(MGdf) )
def test_hessian(self, f=None, n=5): """ test Hessian with FD approx around point f """ if f == None: f = self.f_true pm = [1.0, -1.0] eps = 1e-5 self.Hessian(f) for nn in xrange(1, n + 1): expr = dl.Expression("sin(n*pi*x[0]/200)*sin(n*pi*x[1]/100)", n=nn) df = dl.interpolate(expr, self.V) Hdf = (self.Hess * df.vector()).array() MG = [] for sign in pm: setfct(self.g, f) self.g.vector().axpy(sign * eps, df.vector()) self.gradient(self.g) MG.append(self.MG.array()) HFD = (MG[0] - MG[1]) / (2 * eps) print "n={}:\tHFD={:.5e}, Hdf={:.5e}, error={:.2e}".format( nn, np.linalg.norm(HFD), np.linalg.norm(Hdf), np.linalg.norm(Hdf - HFD) / np.linalg.norm(Hdf) )
def update_w(self, alpha): """ update w and re-scale wH """ self.w.vector().axpy(alpha, self.dw.vector()) # project each w (coord-wise) onto unit sphere to get wH (wx, wy) = self.w.split(deepcopy=True) wxa, wya = wx.vector().array(), wy.vector().array() normw = np.sqrt(wxa**2 + wya**2) factorw = [max(1.0, ii) for ii in normw] setfct(wx, wxa/factorw) setfct(wy, wya/factorw) assign(self.wH.sub(0), wx) assign(self.wH.sub(1), wy) # check (wx,wy) = self.wH.split(deepcopy=True) wxa, wya = wx.vector().array(), wy.vector().array() assert np.amax(np.sqrt(wxa**2 + wya**2)) <= 1.0 + 1e-14 # Print results dualresnorm = assemble(self.dualresnorm) normgraddm = assemble(self.normgraddm) print 'line search dual variable: max(|w|)={}, err(w,df)={}, |grad(dm)|={}'.\ format(np.amax(np.sqrt(normw)), np.sqrt(dualresnorm), np.sqrt(normgraddm))
def ftimeincrfwd(self, tt): """ Compute rhs for incremental forward at time tt """ try: index = int(np.where(isequal(self.PDE.times, tt, 1e-14))[0]) except: print 'Error in ftimeincrfwd at time {}'.format(tt) print np.min(np.abs(self.PDE.times-tt)) sys.exit(0) # bhat: bhat*grad(p).grad(qtilde) # assert isequal(tt, self.solfwdi[index][1], 1e-16) setfct(self.p, self.solfwdi[index][0]) self.q.vector().zero() self.q.vector().axpy(1.0, self.C*self.p.vector()) # ahat: ahat*p''*qtilde: setfct(self.p, self.solppfwdi[index][0]) self.q.vector().axpy(1.0, self.get_incra(self.p.vector())) # ABC: if self.PDE.parameters['abc']: setfct(self.phat, self.solpfwdi[index][0]) self.q.vector().axpy(0.5, self.Dp*self.phat.vector()) return -1.0*self.q.vector()
def checkhessfd_med(ObjFctal, Medium, tolgradchk=1e-6, H = [1e-5, 1e-6, 1e-4], doublesided=True): """Finite-difference check for the Hessian of an ObjectiveFunctional object""" lenm = len(ObjFctal.getmarray()) ObjFctal.backup_m() MGref = ObjFctal.getMGarray() if doublesided: factor = [1.0, -1.0] else: factor = [1.0] hessxdir = ObjFctal.srchdir dirfct = ObjFctal.delta_m for textnb, dirct in zip(range(lenm), Medium): # Do computations for analytical Hessian: setfct(dirfct, dirct) ObjFctal.mult(dirfct.vector(), hessxdir.vector()) normhess = np.linalg.norm(hessxdir.vector().array()) print 'Hessian check -- direction {0}: ||H.x||={1:.5e}'\ .format(textnb+1, normhess) # Do computations for FD Hessian: for hh in H: MG = [] for fact in factor: ObjFctal.update_m(ObjFctal.getmcopyarray() + fact*hh*dirct) ObjFctal.solvefwd_cost() ObjFctal.solveadj_constructgrad() MG.append(ObjFctal.getMGarray()) if doublesided: FDHessx = (MG[0] - MG[1])/(2.0*hh) else: FDHessx = (MG[0] - MGref)/hh # Compute errors: err = np.linalg.norm(hessxdir.vector().array()-FDHessx)/normhess if err < tolgradchk: print '\th={0:.1e}: ||FDH.x||={1:.5e}, error={2:.2e} -> OK!'\ .format(hh, np.linalg.norm(FDHessx), err) break else: print '\th={0:.1e}: ||FDH.x||={1:.5e}, error={2:.2e}'\ .format(hh, np.linalg.norm(FDHessx), err) # Restore initial value of m: ObjFctal.restore_m() ObjFctal.solvefwd_cost() ObjFctal.solveadj_constructgrad()
def copy(self): """(hard) copy constructor""" newobj = self.__class__(self.PDE.copy()) setfct(newobj.MG, self.MG) setfct(newobj.Grad, self.Grad) setfct(newobj.srchdir, self.srchdir) newobj.obsop = self.obsop newobj.dd = self.dd newobj.fwdsource = self.fwdsource newobj.srcindex = self.srcindex newobj.tsteps = self.tsteps return newobj
def ftimeincradj(self, tt): """ Compute rhs for incremental adjoint at time tt """ try: indexf = int(np.where(isequal(self.PDE.times, tt, 1e-14))[0]) indexa = int(np.where(isequal(self.PDE.times[::-1], tt, 1e-14))[0]) except: print 'Error in ftimeincradj at time {}'.format(tt) print np.min(np.abs(self.PDE.times-tt)) sys.exit(0) # lamhat * grad(ptilde).grad(v) assert isequal(tt, self.soladj[indexa][1], 1e-16) setfct(self.v, self.soladj[indexa][0]) setfct(self.vhat, self.C*self.v.vector()) # B* B phat assert isequal(tt, self.solincrfwd[indexf][1], 1e-16) setfct(self.phat, self.solincrfwd[indexf][0]) self.vhat.vector().axpy(1.0, self.obsop.incradj(self.phat, tt)) # D'.dot(v) if self.PDE.abc and indexa > 0: setfct(self.v, \ self.soladj[indexa-1][0] - self.soladj[indexa+1][0]) self.vhat.vector().axpy(-.5*self.invDt, self.Dp*self.v.vector()) return -1.0*self.vhat.vector().array()
def ftimeincrfwd(self, tt): """ Compute rhs for incremental forward at time tt """ try: index = int(np.where(isequal(self.PDE.times, tt, 1e-14))[0]) except: print 'Error in ftimeincrfwd at time {}'.format(tt) print np.min(np.abs(self.PDE.times-tt)) sys.exit(0) # lamhat * grad(p).grad(vtilde) assert isequal(tt, self.solfwd[index][1], 1e-16) setfct(self.p, self.solfwd[index][0]) setfct(self.v, self.C*self.p.vector()) # D'.dot(p) if self.PDE.abc and index > 0: setfct(self.p, \ self.solfwd[index+1][0] - self.solfwd[index-1][0]) self.v.vector().axpy(.5*self.invDt, self.Dp*self.p.vector()) return -1.0*self.v.vector().array()
def cost(self, m_in): """ returns the cost functional for self.m=m_in """ setfct(self.m, m_in) return assemble(self.wkformcost)
def solveadj(self, grad=False): self.PDE.set_adj() self.obsop.assemble_rhsadj(self.Bp, self.dd, self.PDE.times, self.PDE.bc) self.PDE.ftime = self.obsop.ftimeadj self.soladj,_ = self.PDE.solve() if grad: self.MGv.zero() if self.PDE.abc: self.vD.vector().zero(); self.pD.vector().zero(); self.p1D.vector().zero(); self.p2D.vector().zero(); index = 0 for fwd, adj, fact in \ zip(self.solfwd, reversed(self.soladj), self.factors): ttf, tta = fwd[1], adj[1] assert isequal(ttf, tta, 1e-16), \ 'tfwd={}, tadj={}, reldiff={}'.format(ttf, tta, abs(ttf-tta)/ttf) setfct(self.p, fwd[0]) setfct(self.v, adj[0]) self.MGv.axpy(fact, assemble(self.wkformgrad)) # self.MGv.axpy(fact, assemble(self.wkformgrad, \ # form_compiler_parameters={'optimize':True,\ # 'representation':'quadrature'})) if self.PDE.abc: if index%2 == 0: self.p2D.vector().axpy(1.0, self.p.vector()) setfct(self.pD, self.p2D) #self.MGv.axpy(1.0*0.5*self.invDt, assemble(self.wkformgradD)) self.MGv.axpy(fact*0.5*self.invDt, assemble(self.wkformgradD)) setfct(self.p2D, -1.0*self.p.vector()) setfct(self.vD, self.v) else: self.p1D.vector().axpy(1.0, self.p.vector()) setfct(self.pD, self.p1D) #self.MGv.axpy(1.0*0.5*self.invDt, assemble(self.wkformgradD)) self.MGv.axpy(fact*0.5*self.invDt, assemble(self.wkformgradD)) setfct(self.p1D, -1.0*self.p.vector()) setfct(self.vD, self.v) index += 1 self.MGv.axpy(self.alpha_reg, self.regularization.grad(self.PDE.lam)) self.solverM.solve(self.Gradv, self.MGv)
def assemble_hessianab(self, a, b): setfct(self.a, a) setfct(self.b, b) self.H = assemble(self.hessian) self.Hprecond = assemble(self.precond)
def gradab(self, ma_in, mb_in): """ ma_in, mb_in = Function(V) """ setfct(self.a, ma_in) setfct(self.b, mb_in) return assemble(self.grad)
def assemble_GNhessian(self, m_in): """ Assemble the Gauss-Newton Hessian at m_in """ setfct(self.m, m_in) self.H = assemble(self.wkformGNhess)
def mult(self, abhat, y): """ mult(self, abhat, y): return y = Hessian * abhat inputs: y, abhat = Function(V).vector() """ setfct(self.ab, abhat) ahat, bhat = self.ab.split(deepcopy=True) setfct(self.ahat, ahat) setfct(self.bhat, bhat) if not self.inverta: self.ahat.vector().zero() if not self.invertb: self.bhat.vector().zero() self.C = assemble(self.wkformrhsincrb) if not self.PDE.parameters['lumpM']: self.E = assemble(self.wkformrhsincra) if self.PDE.parameters['abc']: self.Dp = assemble(self.wkformincrrhsABC) t0, t1 = self.tsteps[0], self.tsteps[-1]+1 # Compute Hessian*abhat self.ab.vector().zero() yaF_local, ybF_local = self.ab.split(deepcopy=True) ya_local, yb_local = yaF_local.vector(), ybF_local.vector() # iterate over sources: for self.solfwdi, self.solpfwdi, self.solppfwdi, \ self.soladji, self.solpadji, self.solppadji \ in izip(self.solfwd, self.solpfwd, self.solppfwd, \ self.soladj, self.solpadj, self.solppadj): # incr. fwd self.PDE.set_fwd() self.PDE.ftime = self.ftimeincrfwd self.solincrfwd,solpincrfwd,self.solppincrfwd,_ = self.PDE.solve() self.PDEcount += 1 # incr. adj self.PDE.set_adj() self.PDE.ftime = self.ftimeincradj solincradj,_,_,_ = self.PDE.solve() self.PDEcount += 1 # assemble Hessian-vect product: for fwd, adj, fwdp, incrfwdp, \ fwdpp, incrfwdpp, incrfwd, incradj, fact \ in izip(self.solfwdi[t0:t1], self.soladji[::-1][t0:t1],\ self.solpfwdi[t0:t1], solpincrfwd[t0:t1], \ self.solppfwdi[t0:t1], self.solppincrfwd[t0:t1],\ self.solincrfwd[t0:t1], solincradj[::-1][t0:t1], self.factors[t0:t1]): # ttf, tta, ttf2 = incrfwd[1], incradj[1], fwd[1] # assert isequal(ttf, tta, 1e-16), 'tfwd={}, tadj={}, reldiff={}'.\ # format(ttf, tta, abs(ttf-tta)/ttf) # assert isequal(ttf, ttf2, 1e-16), 'tfwd={}, tadj={}, reldiff={}'.\ # format(ttf, ttf2, abs(ttf-ttf2)/ttf) setfct(self.q, adj[0]) setfct(self.qhat, incradj[0]) if self.invertb: # Hessian b setfct(self.p, fwd[0]) setfct(self.phat, incrfwd[0]) if self.GN: yb_local.axpy(fact, assemble(self.wkformhessbGN)) else: yb_local.axpy(fact, assemble(self.wkformhessb)) if self.inverta: # Hessian a setfct(self.p, fwdpp[0]) setfct(self.phat, incrfwdpp[0]) ya_local.axpy(fact, self.get_hessiana()) if self.PDE.parameters['abc']: if not self.GN: setfct(self.p, incrfwdp[0]) if self.inverta: ya_local.axpy(0.5*fact, assemble(self.wkformgradaABC)) if self.invertb: yb_local.axpy(0.5*fact, assemble(self.wkformgradbABC)) setfct(self.p, fwdp[0]) setfct(self.q, incradj[0]) if self.inverta: ya_local.axpy(0.5*fact, assemble(self.wkformgradaABC)) if self.invertb: yb_local.axpy(0.5*fact, assemble(self.wkformgradbABC)) if not self.GN: setfct(self.q, adj[0]) if self.inverta: ya_local.axpy(0.25*fact, assemble(self.wkformhessaABC)) if self.invertb: yb_local.axpy(0.25*fact, assemble(self.wkformhessbABC)) yaF, ybF = self.ab.split(deepcopy=True) MPIAllReduceVector(ya_local, yaF.vector(), self.mpicomm_global) MPIAllReduceVector(yb_local, ybF.vector(), self.mpicomm_global) self.ab.vector().zero() if self.inverta: assign(self.ab.sub(0), yaF) if self.invertb: assign(self.ab.sub(1), ybF) y.zero() y.axpy(1.0/len(self.fwdsource[1]), self.ab.vector()) if DEBUG: print 'Hess_misfit={}, Hess_reg={}'.format(\ y.norm('l2'),\ self.regularization.hessianab(self.ahat.vector(),\ self.bhat.vector()).norm('l2')) y.axpy(self.alpha_reg, \ self.regularization.hessianab(self.ahat.vector(), self.bhat.vector()))
def gradabvect(self, m1, m2): setfct(self.tmpm1, m1) setfct(self.tmpm2, m2) return self.gradab(self.tmpm1, self.tmpm2)
def grad(self, m_in): """ returns the gradient (in vector format) evaluated at self.m = m_in """ setfct(self.m, m_in) self.H = None return assemble(self.wkformgrad)
def mult(self, lamhat, y): """ mult(self, lamhat, y): return y = Hessian * lamhat inputs: y, lamhat = Function(V).vector() """ self.regularization.assemble_hessian(lamhat) setfct(self.lamhat, lamhat) self.C = assemble(self.wkformrhsincr) if self.PDE.abc: self.Dp = assemble(self.wkformDprime) # solve for phat self.PDE.set_fwd() self.PDE.ftime = self.ftimeincrfwd self.solincrfwd,_ = self.PDE.solve() # solve for vhat self.PDE.set_adj() self.PDE.ftime = self.ftimeincradj self.solincradj,_ = self.PDE.solve() # Compute Hessian*lamhat y.zero() index = 0 if self.PDE.abc: self.vD.vector().zero(); self.vhatD.vector().zero(); self.p1D.vector().zero(); self.p2D.vector().zero(); self.p1hatD.vector().zero(); self.p2hatD.vector().zero(); for fwd, adj, incrfwd, incradj, fact in \ zip(self.solfwd, reversed(self.soladj), \ self.solincrfwd, reversed(self.solincradj), self.factors): ttf, tta, ttf2 = incrfwd[1], incradj[1], fwd[1] assert isequal(ttf, tta, 1e-16), 'tfwd={}, tadj={}, reldiff={}'.\ format(ttf, tta, abs(ttf-tta)/ttf) assert isequal(ttf, ttf2, 1e-16), 'tfwd={}, tadj={}, reldiff={}'.\ format(ttf, ttf2, abs(ttf-ttf2)/ttf) setfct(self.p, fwd[0]) setfct(self.v, adj[0]) setfct(self.phat, incrfwd[0]) setfct(self.vhat, incradj[0]) y.axpy(fact, assemble(self.wkformhess)) if self.PDE.abc: if index%2 == 0: self.p2D.vector().axpy(1.0, self.p.vector()) self.p2hatD.vector().axpy(1.0, self.phat.vector()) setfct(self.dp, self.p2D) setfct(self.dph, self.p2hatD) y.axpy(1.0*0.5*self.invDt, assemble(self.wkformhessD)) setfct(self.p2D, -1.0*self.p.vector()) setfct(self.p2hatD, -1.0*self.phat.vector()) else: self.p1D.vector().axpy(1.0, self.p.vector()) self.p1hatD.vector().axpy(1.0, self.phat.vector()) setfct(self.dp, self.p1D) setfct(self.dph, self.p1hatD) y.axpy(1.0*0.5*self.invDt, assemble(self.wkformhessD)) setfct(self.p1D, -1.0*self.p.vector()) setfct(self.p1hatD, -1.0*self.phat.vector()) setfct(self.vD, self.v) setfct(self.vhatD, self.vhat) index += 1 # add regularization term y.axpy(self.alpha_reg, self.regularization.hessian(lamhat))
def update(self, parameters_m): assert not self.timestepper == None, "You need to set a time stepping method" # Time options: if parameters_m.has_key('t0'): self.t0 = parameters_m['t0'] if parameters_m.has_key('tf'): self.tf = parameters_m['tf'] if parameters_m.has_key('Dt'): self.Dt = parameters_m['Dt'] if parameters_m.has_key('t0') or parameters_m.has_key('tf') or parameters_m.has_key('Dt'): self.Nt = int(round((self.tf-self.t0)/self.Dt)) self.Tf = self.t0 + self.Dt*self.Nt self.times = np.linspace(self.t0, self.Tf, self.Nt+1) assert isequal(self.times[1]-self.times[0], self.Dt, 1e-16), "Dt modified" self.Dt = self.times[1] - self.times[0] assert isequal(self.Tf, self.tf, 1e-2), "Final time differs by more than 1%" if not isequal(self.Tf, self.tf, 1e-12): print 'Final time modified from {} to {} ({}%)'.\ format(self.tf, self.Tf, abs(self.Tf-self.tf)/self.tf) # Initial conditions: if parameters_m.has_key('u0init'): self.u0init = parameters_m['u0init'] if parameters_m.has_key('utinit'): self.utinit = parameters_m['utinit'] if parameters_m.has_key('u1init'): self.u1init = parameters_m['u1init'] if parameters_m.has_key('um1init'): self.um1init = parameters_m['um1init'] # Medium parameters: setfct(self.lam, parameters_m['lambda']) if self.verbose: print 'lambda updated ' if self.elastic == True: setfct(self.mu, parameters_m['mu']) if self.verbose: print 'mu updated' if self.verbose: print 'assemble K', self.K = assemble(self.weak_k) if self.verbose: print ' -- K assembled' if parameters_m.has_key('rho'): setfct(self.rho, parameters_m['rho']) # Mass matrix: if self.verbose: print 'rho updated\nassemble M', Mfull = assemble(self.weak_m) if self.lump: self.solverM = LumpedMatrixSolverS(self.V) self.solverM.set_operator(Mfull, self.bc) self.M = self.solverM else: if mpisize == 1: self.solverM = LUSolver() self.solverM.parameters['reuse_factorization'] = True self.solverM.parameters['symmetric'] = True else: self.solverM = KrylovSolver('cg', 'amg') self.solverM.parameters['report'] = False self.M = Mfull if not self.bc == None: self.bc.apply(Mfull) self.solverM.set_operator(Mfull) if self.verbose: print ' -- M assembled' # Matrix D for abs BC if self.abc == True: if self.verbose: print 'assemble D', Mfull = assemble(self.weak_m) Dfull = assemble(self.weak_d) if self.lumpD: self.D = LumpedMatrixSolverS(self.V) self.D.set_operator(Dfull, None, False) if self.lump: self.solverMplD = LumpedMatrixSolverS(self.V) self.solverMplD.set_operators(Mfull, Dfull, .5*self.Dt, self.bc) self.MminD = LumpedMatrixSolverS(self.V) self.MminD.set_operators(Mfull, Dfull, -.5*self.Dt, self.bc) else: self.D = Dfull if self.verbose: print ' -- D assembled' else: self.D = 0.0
def assemble_hessianab(self, m1, m2): """ Assemble Hessian matrix for regularization """ setfct(self.m1, m1) setfct(self.m2, m2) self.H = assemble(self.hessian)
def assemble_hessianab(self, m1, m2): setfct(self.m1, m1) setfct(self.m2, m2) assign(self.m.sub(0), self.m1) assign(self.m.sub(1), self.m2) self.regTV.assemble_hessian(self.m)
def grad(self, uin, udin): isFunction(uin) isFunction(udin) setfct(self.diff, uin.vector() - udin.vector()) return self.W * self.diffv
def costfct_F(self, uin, udin): isFunction(uin) isFunction(udin) setfct(self.diff, uin.vector()-udin.vector()) return 0.5 * (self.W*self.diffv).inner(self.diffv)
def costabvect(self, m1, m2): setfct(self.tmpm1, m1) setfct(self.tmpm2, m2) return self.costab(self.tmpm1, self.tmpm2)
def costab(self, ma_in, mb_in): setfct(self.a, ma_in) setfct(self.b, mb_in) return assemble(self.cost)
def grad(self, m_in): """ returns the gradient (in vector format) evaluated at self.m = m_in """ setfct(self.m, m_in) return assemble(self.wkformgrad)
def compute_dw(self, dm): """ Compute dw """ setfct(self.dm, dm) b = assemble(self.rhswwk) solve(self.Mw, self.dw.vector(), b)
def gradab(self, m1, m2): """ returns gradient at (m1,m2) as a vector """ setfct(self.m1, m1) setfct(self.m2, m2) return assemble(self.gradm)
def cost(self, m_in): """ returns the cost functional for self.m=m_in """ setfct(self.m, m_in) self.H = None return assemble(self.wkformcost)
def costab(self, m1, m2): """ Compute value of cost function at (m1,m2) """ setfct(self.m1, m1) setfct(self.m2, m2) return assemble(self.wkformcost)
def assemble_hessian(self, m_in): """ Assemble the Hessian of TV at m_in """ setfct(self.m, m_in) self.H = assemble(self.wkformhess)
def cost(self, m): """ evaluate the cost functional at m """ setfct(self.m, m) return assemble(self.wkformcost)
def update_m(self, medparam): """ medparam contains both med parameters """ setfct(self.ab, medparam) a, b = self.ab.split(deepcopy=True) self.update_PDE({'a':a, 'b':b})
def solveadj(self, grad=False): self.PDE.set_adj() self.soladj, self.solpadj, self.solppadj = [], [], [] for Bp, dd in zip(self.Bp, self.dd): self.obsop.assemble_rhsadj(Bp, dd, self.PDE.times, self.PDE.bc) self.PDE.ftime = self.obsop.ftimeadj soladj,solpadj,solppadj,_ = self.PDE.solve() self.soladj.append(soladj) self.solpadj.append(solpadj) self.solppadj.append(solppadj) self.PDEcount += 1 if grad: self.MG.vector().zero() MGa_local, MGb_local = self.MG.split(deepcopy=True) MGav_local, MGbv_local = MGa_local.vector(), MGb_local.vector() t0, t1 = self.tsteps[0], self.tsteps[-1]+1 for solfwd, solpfwd, solppfwd, soladj in \ izip(self.solfwd, self.solpfwd, self.solppfwd, self.soladj): for fwd, fwdp, fwdpp, adj, fact in \ izip(solfwd[t0:t1], solpfwd[t0:t1], solppfwd[t0:t1],\ soladj[::-1][t0:t1], self.factors[t0:t1]): setfct(self.q, adj[0]) if self.inverta: # gradient a setfct(self.p, fwdpp[0]) MGav_local.axpy(fact, self.get_gradienta()) if self.invertb: # gradient b setfct(self.p, fwd[0]) assemble(form=self.wkformgradb, tensor=self.wkformgradbout) MGbv_local.axpy(fact, self.wkformgradbout) if self.PDE.parameters['abc']: setfct(self.p, fwdp[0]) if self.inverta: assemble(form=self.wkformgradaABC, tensor=self.wkformgradaABCout) MGav_local.axpy(0.5*fact, self.wkformgradaABCout) if self.invertb: assemble(form=self.wkformgradbABC, tensor=self.wkformgradbABCout) MGbv_local.axpy(0.5*fact, self.wkformgradbABCout) MGa, MGb = self.MG.split(deepcopy=True) MPIAllReduceVector(MGav_local, MGa.vector(), self.mpicomm_global) MPIAllReduceVector(MGbv_local, MGb.vector(), self.mpicomm_global) setfct(MGa, MGa.vector()/len(self.fwdsource[1])) setfct(MGb, MGb.vector()/len(self.fwdsource[1])) self.MG.vector().zero() if self.inverta: assign(self.MG.sub(0), MGa) if self.invertb: assign(self.MG.sub(1), MGb) if DEBUG: print 'grad_misfit={}, grad_reg={}'.format(\ self.MG.vector().norm('l2'),\ self.regularization.gradab(self.PDE.a, self.PDE.b).norm('l2')) self.MG.vector().axpy(self.alpha_reg, \ self.regularization.gradab(self.PDE.a, self.PDE.b)) try: self.solverM.solve(self.Grad.vector(), self.MG.vector()) except: # if |G|<<1, first residuals may diverge # caveat: Hope that ALL processes throw an exception pseudoGradnorm = np.sqrt(self.MGv.inner(self.MGv)) if pseudoGradnorm < 1e-8: print '*** Warning: Increasing divergence_limit for Mass matrix solver' self.solverM.parameters["divergence_limit"] = 1e6 self.solverM.solve(self.Grad.vector(), self.MG.vector()) else: print '*** Error: Problem with Mass matrix solver' sys.exit(1)