def solve_alpha_M_beta_F(self, alpha, beta, b, t): """Solve :code:`alpha * M * u + beta * F(u, t) = b` with Dirichlet conditions. """ matrix = alpha * self.M + beta * self.A # See above for float conversion right_hand_side = -float(beta) * self.b.copy() if b: right_hand_side += b for bc in self.dirichlet_bcs: bc.apply(matrix, right_hand_side) # TODO proper preconditioner for convection if self.convection: # Use HYPRE-Euclid instead of ILU for parallel computation. # However, this PC sometimes fails. # solver = KrylovSolver('gmres', 'hypre_euclid') # Fallback: solver = LUSolver() else: solver = KrylovSolver("gmres", "hypre_amg") solver.parameters["relative_tolerance"] = 1.0e-13 solver.parameters["absolute_tolerance"] = 0.0 solver.parameters["maximum_iterations"] = 100 solver.parameters["monitor_convergence"] = True solver.set_operator(matrix) u = Function(self.Q) solver.solve(u.vector(), right_hand_side) return u
def assert_solves( mesh: Mesh, diffusion: Coefficient, convection: Optional[Coefficient], reaction: Optional[Coefficient], source: Coefficient, exact: Coefficient, l2_tol: Optional[float] = 1.0e-8, h1_tol: Optional[float] = 1.0e-6, ): eafe_matrix = eafe_assemble(mesh, diffusion, convection, reaction) pw_linears = FunctionSpace(mesh, "Lagrange", 1) test_function = TestFunction(pw_linears) rhs_vector = assemble(source * test_function * dx) bc = DirichletBC(pw_linears, exact, lambda _, on_bndry: on_bndry) bc.apply(eafe_matrix, rhs_vector) solution = Function(pw_linears) solver = LUSolver(eafe_matrix, "default") solver.parameters["symmetric"] = False solver.solve(solution.vector(), rhs_vector) l2_err: float = errornorm(exact, solution, "l2", 3) assert l2_err <= l2_tol, f"L2 error too large: {l2_err} > {l2_tol}" h1_err: float = errornorm(exact, solution, "H1", 3) assert h1_err <= h1_tol, f"H1 error too large: {h1_err} > {h1_tol}"
def direct_solve(A, b, W, which='umfpack'): '''inv(A)*b''' print 'Solving system of size %d' % A.size(0) # NOTE: umfpack sometimes blows up, MUMPS produces crap more often than not if isinstance(W, list): wh = ii_Function(W) LUSolver(which).solve(A, wh.vector(), b) print('|b-Ax| from direct solver', (A * wh.vector() - b).norm('linf')) return wh wh = Function(W) LUSolver(which).solve(A, wh.vector(), b) print('|b-Ax| from direct solver', (A * wh.vector() - b).norm('linf')) if isinstance( W.ufl_element(), (ufl.VectorElement, ufl.TensorElement)) or W.num_sub_spaces() == 1: return ii_Function([W], [wh]) # Now get components Wblock = serialize_mixed_space(W) wh = wh.split(deepcopy=True) return ii_Function(Wblock, wh)
def _get_constant_pressure(self, W): w = TrialFunction(W) w_ = TestFunction(W) p_ = self.test_functions()["p"] A, b = assemble_system(inner(w, w_) * dx, p_ * dx) null_fcn = Function(W) solver = LUSolver("mumps") solver.solve(A, null_fcn.vector(), b) return null_fcn
def __init__(self, *args, **kwargs): """ Create solver for :py:class:`SemiDecoupled <muflon.functions.discretization.SemiDecoupled>` discretization scheme. See :py:class:`Solver <muflon.solving.solvers.Solver>` for the list of valid initialization arguments. """ super(SemiDecoupled, self).__init__(*args, **kwargs) # Extract solution functions DS = self.data["model"].discretization_scheme() w_ch, w_ns = DS.solution_ctl() # Adjust bcs bcs_ch = [] bcs_ns = [] _bcs = self.data["model"].bcs() for bc_v in _bcs.get("v", []): assert isinstance(bc_v, tuple) assert len(bc_v) == len(w_ns.sub(0)) bcs_ns += [bc for bc in bc_v if bc is not None] bcs_ns += [bc for bc in _bcs.get("p", [])] # FIXME: Deal with possible bcs for ``phi`` and ``th`` # Prepare solver for CH part F = self.data["forms"]["nln"] J = derivative(F, w_ch) # Store solvers and collect other data self.data["problem_ch"] = self.CHProblem(F, bcs_ch, J) self.data["solver"] = OrderedDict() self.data["solver"]["CH"] = OrderedDict() self.data["solver"]["CH"]["lin"] = LUSolver("mumps") # NOTE: Initialization of nonlinear solver is postponed until setup self.data["solver"]["NS"] = LUSolver("mumps") self.data["sol_ch"] = w_ch self.data["sol_ns"] = w_ns self.data["bcs_ns"] = bcs_ns # Preparation for tackling singular systems if self._flags["fix_p"]: null_space, null_fcn = DS.build_pressure_null_space() self.data["null_space"] = null_space self.data["null_fcn"] = null_fcn # Store number of iterations self.iters = OrderedDict() self.iters["CH"] = [0, 0] # (total, last solve) self.iters["NS"] = [0, 0] # (total, last solve)
def setUp(self): mesh = UnitSquareMesh(5, 5, 'crossed') self.V = FunctionSpace(mesh, 'Lagrange', 5) self.u = Function(self.V) self.uM = Function(self.V) self.uMdiag = Function(self.V) test = TestFunction(self.V) trial = TrialFunction(self.V) m = test * trial * dx self.M = assemble(m) self.solver = LUSolver() self.solver.parameters['reuse_factorization'] = True self.solver.parameters['symmetric'] = True self.solver.set_operator(self.M) self.ones = np.ones(self.V.dim())
def __init__(self, *args, **kwargs): """ Create linear solver for :py:class:`FullyDecoupled \ <muflon.functions.discretization.FullyDecoupled>` discretization scheme. See :py:class:`Solver <muflon.solving.solvers.Solver>` for the list of valid initialization arguments. """ super(FullyDecoupled, self).__init__(*args, **kwargs) # Create solvers solver = OrderedDict() solver["phi"] = LUSolver("mumps") solver["chi"] = LUSolver("mumps") solver["v"] = LUSolver("mumps") solver["p"] = LUSolver("mumps") self.data["solver"] = solver # Initialize flags self._flags["setup"] = False
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'] if self.Parameters.has_key('m0'): self.m0 = self.Parameters['m0'].copy(deepcopy=True) isFunction(self.m0) else: self.m0 = Function(self.Vm) 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 = PETScMatrix() assemble(inner(self.mtrial, self.mtest) * dx, tensor=self.M) # preconditioner is Gamma^{-1}: if self.beta > 1e-16: self.precond = self.gamma * self.R + self.beta * self.M else: self.precond = self.gamma * self.R + (1e-14) * self.M # Discrete operator K: self.K = self.gamma * self.R + self.beta * self.M # Get eigenvalues for M: self.eigsolM = SLEPcEigenSolver(self.M) self.eigsolM.solve() # Solver for M^{-1}: self.solverM = LUSolver() self.solverM.parameters['reuse_factorization'] = True self.solverM.parameters['symmetric'] = True self.solverM.set_operator(self.M) # Solver for K^{-1}: self.solverK = LUSolver() self.solverK.parameters['reuse_factorization'] = True self.solverK.parameters['symmetric'] = True self.solverK.set_operator(self.K)
def _set_fluid_default_parameters(self): fluid = df.Parameters(Physics.FLUID.value) fluid.add("dt", 1e-3) fluid.add("dummy_parameter", False) # Add default parameters from both LU and Krylov solvers fluid.add(LUSolver.default_parameters()) fluid.add(PETScKrylovSolver.default_parameters()) # Add solver parameters fluid.add(df.Parameters("Solver")) fluid["Solver"].add("dummy_parameter", False) self.add(fluid)
def _set_porous_default_parameters(self): porous = df.Parameters(Physics.POROUS.value) porous.add("dt", 1e-3) porous.add("dummy_parameter", False) # Add default parameters from both LU and Krylov solvers porous.add(LUSolver.default_parameters()) porous.add(PETScKrylovSolver.default_parameters()) # Add solver parameters porous.add(df.Parameters("Solver")) porous["Solver"].add("dummy_parameter", False) self.add(porous)
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'] if self.Parameters.has_key('m0'): self.m0 = self.Parameters['m0'].copy(deepcopy=True) isFunction(self.m0) else: self.m0 = Function(self.Vm) 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 = PETScMatrix() assemble(inner(self.mtrial, self.mtest)*dx, tensor=self.M) # preconditioner is Gamma^{-1}: if self.beta > 1e-16: self.precond = self.gamma*self.R + self.beta*self.M else: self.precond = self.gamma*self.R + (1e-14)*self.M # Discrete operator K: self.K = self.gamma*self.R + self.beta*self.M # Get eigenvalues for M: self.eigsolM = SLEPcEigenSolver(self.M) self.eigsolM.solve() # Solver for M^{-1}: self.solverM = LUSolver() self.solverM.parameters['reuse_factorization'] = True self.solverM.parameters['symmetric'] = True self.solverM.set_operator(self.M) # Solver for K^{-1}: self.solverK = LUSolver() self.solverK.parameters['reuse_factorization'] = True self.solverK.parameters['symmetric'] = True self.solverK.set_operator(self.K)
def setUp(self): mesh = UnitSquareMesh(5, 5, 'crossed') self.V = FunctionSpace(mesh, 'Lagrange', 5) self.u = Function(self.V) self.uM = Function(self.V) self.uMdiag = Function(self.V) test = TestFunction(self.V) trial = TrialFunction(self.V) m = test*trial*dx self.M = assemble(m) self.solver = LUSolver() self.solver.parameters['reuse_factorization'] = True self.solver.parameters['symmetric'] = True self.solver.set_operator(self.M) self.ones = np.ones(self.V.dim())
def _set_solid_default_parameters(self): solid = df.Parameters(Physics.SOLID.value) solid.add("dt", 1e-3) solid.add("dummy_parameter", False) # Add boundary condtion parameters solid.add(df.Parameters("BoundaryConditions")) solid["BoundaryConditions"].add("base_bc", "fixed") solid["BoundaryConditions"].add("lv_pressure", 10.0) solid["BoundaryConditions"].add("rv_pressure", 0.0) solid["BoundaryConditions"].add("pericardium_spring", 0.0) solid["BoundaryConditions"].add("base_spring", 0.0) # Add default parameters from both LU and Krylov solvers solid.add(NonlinearVariationalSolver.default_parameters()) solid.add(LUSolver.default_parameters()) solid.add(PETScKrylovSolver.default_parameters()) # Add solver parameters solid.add(df.Parameters("Solver")) solid["Solver"].add("dummy_parameter", False) self.add(solid)
def solve_alpha_M_beta_F(self, alpha, beta, b, t): '''Solve alpha * M * u + beta * F(u, t) = b for u. ''' A = alpha * self.M + beta * self.A # See above for float conversion right_hand_side = - float(beta) * self.b.copy() if b: right_hand_side += b for bc in self.bcs: bc.apply(A, b) # The Krylov solver doesn't converge solver = LUSolver() solver.set_operator(A) u = Function(self.V) solver.solve(u.vector(), b) return u
class ObjectiveFunctional(LinearOperator): """ Provides data misfit, gradient and Hessian information for the data misfit part of a time-independent symmetric inverse problem. """ __metaclass__ = abc.ABCMeta # Instantiation def __init__(self, V, Vm, bc, bcadj, \ RHSinput=[], ObsOp=[], UD=[], Regul=[], Data=[], plot=False, \ mycomm=None): # Define test, trial and all other functions self.trial = TrialFunction(V) self.test = TestFunction(V) self.mtrial = TrialFunction(Vm) self.mtest = TestFunction(Vm) self.rhs = Function(V) self.m = Function(Vm) self.mcopy = Function(Vm) self.srchdir = Function(Vm) self.delta_m = Function(Vm) self.MG = Function(Vm) self.Grad = Function(Vm) self.Gradnorm = 0.0 self.lenm = len(self.m.vector().array()) self.u = Function(V) self.ud = Function(V) self.diff = Function(V) self.p = Function(V) # Define weak forms to assemble A, C and E self._wkforma() self._wkformc() self._wkforme() # Store other info: self.ObsOp = ObsOp self.UD = UD self.reset() # Initialize U, C and E to [] self.Data = Data self.GN = 1.0 # GN = 0.0 => GN Hessian; = 1.0 => full Hessian # Operators and bc LinearOperator.__init__(self, self.delta_m.vector(), \ self.delta_m.vector()) self.bc = bc self.bcadj = bcadj self._assemble_solverM(Vm) self.assemble_A() self.assemble_RHS(RHSinput) self.Regul = Regul # Counters, tolerances and others self.nbPDEsolves = 0 # Updated when solve_A called self.nbfwdsolves = 0 # Counter for plots self.nbadjsolves = 0 # Counter for plots self._set_plots(plot) # MPI: self.mycomm = mycomm try: self.myrank = MPI.rank(self.mycomm) except: self.myrank = 0 def copy(self): """Define a copy method""" V = self.trial.function_space() Vm = self.mtrial.function_space() newobj = self.__class__(V, Vm, self.bc, self.bcadj, [], self.ObsOp, \ self.UD, self.Regul, self.Data, False) newobj.RHS = self.RHS newobj.update_m(self.m) return newobj def mult(self, mhat, y): """mult(self, mhat, y): do y = Hessian * mhat member self.GN sets full Hessian (=1.0) or GN Hessian (=0.0)""" N = self.Nbsrc # Number of sources y[:] = np.zeros(self.lenm) for C, E in zip(self.C, self.E): # Solve for uhat C.transpmult(mhat, self.rhs.vector()) self.bcadj.apply(self.rhs.vector()) self.solve_A(self.u.vector(), -self.rhs.vector()) # Solve for phat E.transpmult(mhat, self.rhs.vector()) Etmhat = self.rhs.vector().array() self.rhs.vector().axpy(1.0, self.ObsOp.incradj(self.u)) self.bcadj.apply(self.rhs.vector()) self.solve_A(self.p.vector(), -self.rhs.vector()) # Compute Hessian*x: y.axpy(1.0/N, C * self.p.vector()) y.axpy(self.GN/N, E * self.u.vector()) y.axpy(1.0, self.Regul.hessian(mhat)) # Getters def getm(self): return self.m def getmarray(self): return self.m.vector().array() def getmcopyarray(self): return self.mcopy.vector().array() def getVm(self): return self.mtrial.function_space() def getMGarray(self): return self.MG.vector().array() def getMGvec(self): return self.MG.vector() def getGradarray(self): return self.Grad.vector().array() def getGradnorm(self): return self.Gradnorm def getsrchdirarray(self): return self.srchdir.vector().array() def getsrchdirvec(self): return self.srchdir.vector() def getsrchdirnorm(self): return np.sqrt((self.MM*self.getsrchdirvec()).inner(self.getsrchdirvec())) def getgradxdir(self): return self.gradxdir def getcost(self): return self.cost, self.misfit, self.regul def getprecond(self): Prec = PETScKrylovSolver("richardson", "amg") Prec.parameters["maximum_iterations"] = 1 Prec.parameters["error_on_nonconvergence"] = False Prec.parameters["nonzero_initial_guess"] = False Prec.set_operator(self.Regul.get_precond()) return Prec def getMass(self): return self.MM # Setters def setsrchdir(self, arr): self.srchdir.vector()[:] = arr def setgradxdir(self, valueloc): """Sum all local results for Grad . Srch_dir""" try: valueglob = MPI.sum(self.mycomm, valueloc) except: valueglob = valueloc self.gradxdir = valueglob # Solve def solvefwd(self, cost=False): """Solve fwd operators for given RHS""" self.nbfwdsolves += 1 if self.ObsOp.noise: self.noise = 0.0 if self.plot: self.plotu = PlotFenics(self.plotoutdir) self.plotu.set_varname('u{0}'.format(self.nbfwdsolves)) if cost: self.misfit = 0.0 for ii, rhs in enumerate(self.RHS): self.solve_A(self.u.vector(), rhs) if self.plot: self.plotu.plot_vtk(self.u, ii) u_obs, noiselevel = self.ObsOp.obs(self.u) self.U.append(u_obs) if self.ObsOp.noise: self.noise += noiselevel if cost: self.misfit += self.ObsOp.costfct(u_obs, self.UD[ii]) self.C.append(assemble(self.c)) if cost: self.misfit /= len(self.U) self.regul = self.Regul.cost(self.m) self.cost = self.misfit + self.regul if self.ObsOp.noise and self.myrank == 0: print 'Total noise in data misfit={:.5e}\n'.\ format(self.noise*.5/len(self.U)) self.ObsOp.noise = False # Safety if self.plot: self.plotu.gather_vtkplots() def solvefwd_cost(self): """Solve fwd operators for given RHS and compute cost fct""" self.solvefwd(True) def solveadj(self, grad=False): """Solve adj operators""" self.nbadjsolves += 1 if self.plot: self.plotp = PlotFenics(self.plotoutdir) self.plotp.set_varname('p{0}'.format(self.nbadjsolves)) self.Nbsrc = len(self.UD) if grad: self.MG.vector()[:] = np.zeros(self.lenm) for ii, C in enumerate(self.C): self.ObsOp.assemble_rhsadj(self.U[ii], self.UD[ii], \ self.rhs, self.bcadj) self.solve_A(self.p.vector(), self.rhs.vector()) if self.plot: self.plotp.plot_vtk(self.p, ii) self.E.append(assemble(self.e)) if grad: self.MG.vector().axpy(1.0/self.Nbsrc, \ C * self.p.vector()) if grad: self.MG.vector().axpy(1.0, self.Regul.grad(self.m)) self.solverM.solve(self.Grad.vector(), self.MG.vector()) self.Gradnorm = np.sqrt(self.Grad.vector().inner(self.MG.vector())) if self.plot: self.plotp.gather_vtkplots() def solveadj_constructgrad(self): """Solve adj operators and assemble gradient""" self.solveadj(True) # Assembler def assemble_A(self): """Assemble operator A(m)""" self.A = assemble(self.a) self.bc.apply(self.A) self.set_solver() def solve_A(self, b, f): """Solve system of the form A.b = f, with b and f in form to be used in solver.""" self.solver.solve(b, f) self.nbPDEsolves += 1 def assemble_RHS(self, RHSin): """Assemble RHS for fwd solve""" if RHSin == []: self.RHS = None else: self.RHS = [] for rhs in RHSin: if isinstance(rhs, Expression): L = rhs*self.test*dx b = assemble(L) self.bc.apply(b) self.RHS.append(b) else: raise WrongInstanceError("rhs should be Expression") def _assemble_solverM(self, Vm): self.MM = assemble(inner(self.mtrial, self.mtest)*dx) self.solverM = LUSolver() self.solverM.parameters['reuse_factorization'] = True self.solverM.parameters['symmetric'] = True self.solverM.set_operator(self.MM) def _set_plots(self, plot): self.plot = plot if self.plot: filename, ext = splitext(sys.argv[0]) self.plotoutdir = filename + '/Plots/' self.plotvarm = PlotFenics(self.plotoutdir) self.plotvarm.set_varname('m') def plotm(self, index): if self.plot: self.plotvarm.plot_vtk(self.m, index) def gatherm(self): if self.plot: self.plotvarm.gather_vtkplots() # Update param def update_Data(self, Data): """Update Data member""" self.Data = Data self.assemble_A() self.reset() def update_m(self, m): """Update values of parameter m""" if isinstance(m, np.ndarray): self.m.vector()[:] = m elif isinstance(m, Function): self.m.assign(m) elif isinstance(m, float): self.m.vector()[:] = m elif isinstance(m, int): self.m.vector()[:] = float(m) else: raise WrongInstanceError('Format for m not accepted') self.assemble_A() self.reset() def backup_m(self): self.mcopy.assign(self.m) def restore_m(self): self.update_m(self.mcopy) def reset(self): """Reset U, C and E""" self.U = [] self.C = [] self.E = [] def set_solver(self): """Reset solver for fwd operator""" self.solver = LUSolver() self.solver.parameters['reuse_factorization'] = True self.solver.set_operator(self.A) def addPDEcount(self, increment=1): """Increase 'nbPDEsolves' by 'increment'""" self.nbPDEsolves += increment def resetPDEsolves(self): self.nbPDEsolves = 0 # Additional methods for compatibility with CG solver: def init_vector(self, x, dim): """Initialize vector x to be compatible with parameter Does not work in dolfin 1.3.0""" self.MM.init_vector(x, 0) def init_vector130(self): """Initialize vector x to be compatible with parameter""" return Vector(Function(self.mcopy.function_space()).vector()) # Abstract methods @abc.abstractmethod def _wkforma(self): self.a = [] @abc.abstractmethod def _wkformc(self): self.c = [] @abc.abstractmethod def _wkforme(self): self.e = []
class BilaplacianPrior(GaussianPrior): """Gaussian prior Parameters must be a dictionary containing: gamma = multiplicative factor applied to <Grad u, Grad v> term beta = multiplicative factor applied to <u,v> term (default=0.0) m0 = mean (or reference parameter when used as regularization) Vm = function space for parameter cost = 1/2 * (m-m0)^T.R.(m-m0)""" 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'] if self.Parameters.has_key('m0'): self.m0 = self.Parameters['m0'].copy(deepcopy=True) isFunction(self.m0) else: self.m0 = Function(self.Vm) 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 = PETScMatrix() assemble(inner(self.mtrial, self.mtest) * dx, tensor=self.M) # preconditioner is Gamma^{-1}: if self.beta > 1e-16: self.precond = self.gamma * self.R + self.beta * self.M else: self.precond = self.gamma * self.R + (1e-14) * self.M # Discrete operator K: self.K = self.gamma * self.R + self.beta * self.M # Get eigenvalues for M: self.eigsolM = SLEPcEigenSolver(self.M) self.eigsolM.solve() # Solver for M^{-1}: self.solverM = LUSolver() self.solverM.parameters['reuse_factorization'] = True self.solverM.parameters['symmetric'] = True self.solverM.set_operator(self.M) # Solver for K^{-1}: self.solverK = LUSolver() self.solverK.parameters['reuse_factorization'] = True self.solverK.parameters['symmetric'] = True self.solverK.set_operator(self.K) def Minvpriordot(self, vect): """Here M.Gamma^{-1} = K M^{-1} K""" mhat = Function(self.Vm) self.solverM.solve(mhat.vector(), self.K * vect) return self.K * mhat.vector() def apply_sqrtM(self, vect): """Compute M^{1/2}.vect from Vector() vect""" sqrtMv = Function(self.Vm) for ii in range(self.Vm.dim()): r, c, rx, cx = self.eigsolM.get_eigenpair(ii) RX = Vector(rx) sqrtMv.vector().axpy( np.sqrt(r) * np.dot(rx.array(), vect.array()), RX) return sqrtMv.vector() def Ldot(self, vect): """Here L = K^{-1} M^{1/2}""" Lb = Function(self.Vm) self.solverK.solve(Lb.vector(), self.apply_sqrtM(vect)) return Lb.vector()
class ObjectiveAcoustic(LinearOperator): """ Computes data misfit, gradient and Hessian evaluation for the seismic inverse problem using acoustic wave data """ #TODO: add support for multiple sources # CONSTRUCTORS: def __init__(self, acousticwavePDE, regularization=None): """ Input: acousticwavePDE should be an instantiation from class AcousticWave """ self.PDE = acousticwavePDE self.PDE.exact = None self.fwdsource = self.PDE.ftime self.MG = Function(self.PDE.Vl) self.MGv = self.MG.vector() self.Grad = Function(self.PDE.Vl) self.Gradv = self.Grad.vector() self.srchdir = Function(self.PDE.Vl) self.delta_m = Function(self.PDE.Vl) LinearOperator.__init__(self, self.MG.vector(), self.MG.vector()) self.obsop = None # Observation operator self.dd = None # observations if regularization == None: self.regularization = ZeroRegularization() else: self.regularization = regularization self.alpha_reg = 1.0 # gradient self.lamtest, self.lamtrial = TestFunction(self.PDE.Vl), TrialFunction(self.PDE.Vl) self.p, self.v = Function(self.PDE.V), Function(self.PDE.V) self.wkformgrad = inner(self.lamtest*nabla_grad(self.p), nabla_grad(self.v))*dx # incremental rhs self.lamhat = Function(self.PDE.Vl) self.ptrial, self.ptest = TrialFunction(self.PDE.V), TestFunction(self.PDE.V) self.wkformrhsincr = inner(self.lamhat*nabla_grad(self.ptrial), nabla_grad(self.ptest))*dx # Hessian self.phat, self.vhat = Function(self.PDE.V), Function(self.PDE.V) self.wkformhess = inner(self.lamtest*nabla_grad(self.phat), nabla_grad(self.v))*dx \ + inner(self.lamtest*nabla_grad(self.p), nabla_grad(self.vhat))*dx # Mass matrix: weak_m = inner(self.lamtrial,self.lamtest)*dx Mass = assemble(weak_m) self.solverM = LUSolver() self.solverM.parameters['reuse_factorization'] = True self.solverM.parameters['symmetric'] = True self.solverM.set_operator(Mass) # Time-integration factors self.factors = np.ones(self.PDE.times.size) self.factors[0], self.factors[-1] = 0.5, 0.5 self.factors *= self.PDE.Dt self.invDt = 1./self.PDE.Dt # Absorbing BCs if self.PDE.abc: #TODO: should probably be tested in other situations if self.PDE.lumpD: print '*** Warning: Damping matrix D is lumped. ',\ 'Make sure gradient is consistent.' self.vD, self.pD, self.p1D, self.p2D = Function(self.PDE.V), \ Function(self.PDE.V), Function(self.PDE.V), Function(self.PDE.V) self.wkformgradD = inner(0.5*sqrt(self.PDE.rho/self.PDE.lam)\ *self.pD, self.vD*self.lamtest)*self.PDE.ds(1) self.wkformDprime = inner(0.5*sqrt(self.PDE.rho/self.PDE.lam)\ *self.lamhat*self.ptrial, self.ptest)*self.PDE.ds(1) self.dp, self.dph, self.vhatD = Function(self.PDE.V), \ Function(self.PDE.V), Function(self.PDE.V) self.p1hatD, self.p2hatD = Function(self.PDE.V), Function(self.PDE.V) self.wkformhessD = inner(-0.25*sqrt(self.PDE.rho)/(self.PDE.lam*sqrt(self.PDE.lam))\ *self.lamhat*self.dp, self.vD*self.lamtest)*self.PDE.ds(1) \ + inner(0.5*sqrt(self.PDE.rho/self.PDE.lam)\ *self.dph, self.vD*self.lamtest)*self.PDE.ds(1)\ + inner(0.5*sqrt(self.PDE.rho/self.PDE.lam)\ *self.dp, self.vhatD*self.lamtest)*self.PDE.ds(1) 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 # FORWARD PROBLEM + COST: 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 solvefwd_cost(self): self.solvefwd(True) # ADJOINT PROBLEM + GRAD: #@profile 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 solveadj_constructgrad(self): self.solveadj(True) # HESSIAN: 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 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 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)) # SETTERS + UPDATE: def update_PDE(self, parameters): self.PDE.update(parameters) def update_m(self, lam): self.update_PDE({'lambda':lam}) def set_abc(self, mesh, class_bc_abc, lumpD): self.PDE.set_abc(mesh, class_bc_abc, lumpD) def backup_m(self): self.lam_bkup = self.getmarray() def restore_m(self): self.update_m(self.lam_bkup) def setsrcterm(self, ftime): self.PDE.ftime = ftime # GETTERS: def getmcopyarray(self): return self.lam_bkup def getmarray(self): return self.PDE.lam.vector().array() def getMGarray(self): return self.MGv.array()
def __init__(self, acousticwavePDE, regularization=None): """ Input: acousticwavePDE should be an instantiation from class AcousticWave """ self.PDE = acousticwavePDE self.PDE.exact = None self.fwdsource = self.PDE.ftime self.MG = Function(self.PDE.Vl) self.MGv = self.MG.vector() self.Grad = Function(self.PDE.Vl) self.Gradv = self.Grad.vector() self.srchdir = Function(self.PDE.Vl) self.delta_m = Function(self.PDE.Vl) LinearOperator.__init__(self, self.MG.vector(), self.MG.vector()) self.obsop = None # Observation operator self.dd = None # observations if regularization == None: self.regularization = ZeroRegularization() else: self.regularization = regularization self.alpha_reg = 1.0 # gradient self.lamtest, self.lamtrial = TestFunction(self.PDE.Vl), TrialFunction(self.PDE.Vl) self.p, self.v = Function(self.PDE.V), Function(self.PDE.V) self.wkformgrad = inner(self.lamtest*nabla_grad(self.p), nabla_grad(self.v))*dx # incremental rhs self.lamhat = Function(self.PDE.Vl) self.ptrial, self.ptest = TrialFunction(self.PDE.V), TestFunction(self.PDE.V) self.wkformrhsincr = inner(self.lamhat*nabla_grad(self.ptrial), nabla_grad(self.ptest))*dx # Hessian self.phat, self.vhat = Function(self.PDE.V), Function(self.PDE.V) self.wkformhess = inner(self.lamtest*nabla_grad(self.phat), nabla_grad(self.v))*dx \ + inner(self.lamtest*nabla_grad(self.p), nabla_grad(self.vhat))*dx # Mass matrix: weak_m = inner(self.lamtrial,self.lamtest)*dx Mass = assemble(weak_m) self.solverM = LUSolver() self.solverM.parameters['reuse_factorization'] = True self.solverM.parameters['symmetric'] = True self.solverM.set_operator(Mass) # Time-integration factors self.factors = np.ones(self.PDE.times.size) self.factors[0], self.factors[-1] = 0.5, 0.5 self.factors *= self.PDE.Dt self.invDt = 1./self.PDE.Dt # Absorbing BCs if self.PDE.abc: #TODO: should probably be tested in other situations if self.PDE.lumpD: print '*** Warning: Damping matrix D is lumped. ',\ 'Make sure gradient is consistent.' self.vD, self.pD, self.p1D, self.p2D = Function(self.PDE.V), \ Function(self.PDE.V), Function(self.PDE.V), Function(self.PDE.V) self.wkformgradD = inner(0.5*sqrt(self.PDE.rho/self.PDE.lam)\ *self.pD, self.vD*self.lamtest)*self.PDE.ds(1) self.wkformDprime = inner(0.5*sqrt(self.PDE.rho/self.PDE.lam)\ *self.lamhat*self.ptrial, self.ptest)*self.PDE.ds(1) self.dp, self.dph, self.vhatD = Function(self.PDE.V), \ Function(self.PDE.V), Function(self.PDE.V) self.p1hatD, self.p2hatD = Function(self.PDE.V), Function(self.PDE.V) self.wkformhessD = inner(-0.25*sqrt(self.PDE.rho)/(self.PDE.lam*sqrt(self.PDE.lam))\ *self.lamhat*self.dp, self.vD*self.lamtest)*self.PDE.ds(1) \ + inner(0.5*sqrt(self.PDE.rho/self.PDE.lam)\ *self.dph, self.vD*self.lamtest)*self.PDE.ds(1)\ + inner(0.5*sqrt(self.PDE.rho/self.PDE.lam)\ *self.dp, self.vhatD*self.lamtest)*self.PDE.ds(1)
def _assemble_solverM(self, Vm): self.MM = assemble(inner(self.mtrial, self.mtest)*dx) self.solverM = LUSolver() self.solverM.parameters['reuse_factorization'] = True self.solverM.parameters['symmetric'] = True self.solverM.set_operator(self.MM)
def set_solver(self): """Reset solver for fwd operator""" self.solver = LUSolver() self.solver.parameters['reuse_factorization'] = True self.solver.set_operator(self.A)
class BilaplacianPrior(GaussianPrior): """Gaussian prior Parameters must be a dictionary containing: gamma = multiplicative factor applied to <Grad u, Grad v> term beta = multiplicative factor applied to <u,v> term (default=0.0) m0 = mean (or reference parameter when used as regularization) Vm = function space for parameter cost = 1/2 * (m-m0)^T.R.(m-m0)""" 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'] if self.Parameters.has_key('m0'): self.m0 = self.Parameters['m0'].copy(deepcopy=True) isFunction(self.m0) else: self.m0 = Function(self.Vm) 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 = PETScMatrix() assemble(inner(self.mtrial, self.mtest)*dx, tensor=self.M) # preconditioner is Gamma^{-1}: if self.beta > 1e-16: self.precond = self.gamma*self.R + self.beta*self.M else: self.precond = self.gamma*self.R + (1e-14)*self.M # Discrete operator K: self.K = self.gamma*self.R + self.beta*self.M # Get eigenvalues for M: self.eigsolM = SLEPcEigenSolver(self.M) self.eigsolM.solve() # Solver for M^{-1}: self.solverM = LUSolver() self.solverM.parameters['reuse_factorization'] = True self.solverM.parameters['symmetric'] = True self.solverM.set_operator(self.M) # Solver for K^{-1}: self.solverK = LUSolver() self.solverK.parameters['reuse_factorization'] = True self.solverK.parameters['symmetric'] = True self.solverK.set_operator(self.K) def Minvpriordot(self, vect): """Here M.Gamma^{-1} = K M^{-1} K""" mhat = Function(self.Vm) self.solverM.solve(mhat.vector(), self.K*vect) return self.K * mhat.vector() def apply_sqrtM(self, vect): """Compute M^{1/2}.vect from Vector() vect""" sqrtMv = Function(self.Vm) for ii in range(self.Vm.dim()): r, c, rx, cx = self.eigsolM.get_eigenpair(ii) RX = Vector(rx) sqrtMv.vector().axpy(np.sqrt(r)*np.dot(rx.array(), vect.array()), RX) return sqrtMv.vector() def Ldot(self, vect): """Here L = K^{-1} M^{1/2}""" Lb = Function(self.Vm) self.solverK.solve(Lb.vector(), self.apply_sqrtM(vect)) return Lb.vector()
def main(module_name, ncases, params, petsc_params): ''' Run the test case in module with ncases. Optionally store results in savedir. For some modules there are multiple (which) choices of preconditioners. ''' # Unpack for k, v in params.items(): exec(k + '=v', locals()) RED = '\033[1;37;31m%s\033[0m' print RED % ('\tRunning %s' % module_name) module = __import__(module_name) # no importlib in python2.7 # Setup the MMS case u_true, rhs_data = module.setup_mms(eps) # Setup the convergence monitor if log: params = [('solver', solver), ('precond', str(precond)), ('eps', str(eps))] path = '_'.join([module_name] + ['%s=%s' % pv for pv in params]) path = os.path.join(save_dir if save_dir else '.', path) path = '.'.join([path, 'txt']) else: path = '' memory, residuals = [], [] monitor = module.setup_error_monitor(u_true, memory, path=path) # Sometimes it is usedful to transform the solution before computing # the error. e.g. consider subdomains if hasattr(module, 'setup_transform'): # NOTE: transform take two args for case and the current computed # solution transform = module.setup_transform else: transform = lambda i, x: x print '=' * 79 print '\t\t\tProblem eps = %g' % eps print '=' * 79 for i in ncases: a, L, W = module.setup_problem(i, rhs_data, eps=eps) # Assemble blocks t = Timer('assembly') t.start() AA, bb = map(ii_assemble, (a, L)) print '\tAssembled blocks in %g s' % t.stop() wh = ii_Function(W) if solver == 'direct': # Turn into a (monolithic) PETScMatrix/Vector t = Timer('conversion') t.start() AAm, bbm = map(ii_convert, (AA, bb)) print '\tConversion to PETScMatrix/Vector took %g s' % t.stop() t = Timer('solve') t.start() LUSolver('umfpack').solve(AAm, wh.vector(), bbm) print '\tSolver took %g s' % t.stop() niters = 1 else: # Here we define a Krylov solver using PETSc BB = module.setup_preconditioner(W, precond, eps=eps) ## AA and BB as block_mat ksp = PETSc.KSP().create() # Default is minres if '-ksp_type' not in petsc_params: petsc_params['-ksp_type'] = 'minres' opts = PETSc.Options() for key, value in petsc_params.iteritems(): opts.setValue(key, None if value == 'none' else value) ksp.setOperators(ii_PETScOperator(AA)) ksp.setNormType(PETSc.KSP.NormType.NORM_PRECONDITIONED) # ksp.setTolerances(rtol=1E-6, atol=None, divtol=None, max_it=300) ksp.setConvergenceHistory() # We attach the wrapped preconditioner defined by the module ksp.setPC(ii_PETScPreconditioner(BB, ksp)) ksp.setFromOptions() print ksp.getTolerances() # Want the iterations to start from random wh.block_vec().randomize() # Solve, note the past object must be PETSc.Vec t = Timer('solve') t.start() ksp.solve(as_petsc_nest(bb), wh.petsc_vec()) print '\tSolver took %g s' % t.stop() niters = ksp.getIterationNumber() residuals.append(ksp.getConvergenceHistory()) # Let's check the final size of the residual r_norm = (bb - AA * wh.block_vec()).norm() # Convergence? monitor.send((transform(i, wh), niters, r_norm)) # Only send the final if save_dir: path = os.path.join(save_dir, module_name) for i, wh_i in enumerate(wh): # Renaming to make it easier to save state in Visit/Pareview wh_i.rename('u', str(i)) File('%s_%d.pvd' % (path, i)) << wh_i # Plot relative residual norm if plot: plt.figure() [ plt.semilogy(res / res[0], label=str(i)) for i, res in enumerate(residuals, 1) ] plt.legend(loc='best') plt.show()
class TestLumpedMass(unittest.TestCase): def setUp(self): mesh = UnitSquareMesh(5, 5, 'crossed') self.V = FunctionSpace(mesh, 'Lagrange', 5) self.u = Function(self.V) self.uM = Function(self.V) self.uMdiag = Function(self.V) test = TestFunction(self.V) trial = TrialFunction(self.V) m = test*trial*dx self.M = assemble(m) self.solver = LUSolver() self.solver.parameters['reuse_factorization'] = True self.solver.parameters['symmetric'] = True self.solver.set_operator(self.M) self.ones = np.ones(self.V.dim()) def test00(self): """ Create a lumped solver """ myobj = LumpedMatrixSolver(self.V) def test01_set(self): """ Set operator """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) def test01_entries(self): """ Lump matrix """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) err = 0.0 for index, ii in enumerate(self.M.array()): err += abs(ii.sum() - myobj.Mdiag[index]) self.assertTrue(err < index*1e-16) def test02(self): """ Invert lumped matrix """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) err = 0.0 for ii in range(len(myobj.Mdiag.array())): err += abs(1./myobj.Mdiag[ii] - myobj.invMdiag[ii]) self.assertTrue(err < ii*1e-16) def test03_basic(self): """ solve """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) myobj.solve(self.uMdiag.vector(), myobj.Mdiag) diff = (myobj.one - self.uMdiag.vector()).array() self.assertTrue(np.linalg.norm(diff)/np.linalg.norm(myobj.one.array()) < 1e-14) def test04_mult(self): """ overloaded * operator """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) self.uMdiag.vector().axpy(1.0, myobj*myobj.one) diff = (myobj.Mdiag - self.uMdiag.vector()).array() self.assertTrue(np.linalg.norm(diff)/np.linalg.norm(myobj.Mdiag.array()) < 1e-14) def test10(self): """ Create a lumped solver """ myobj = LumpedMatrixSolverS(self.V) def test11_set(self): """ Set operator """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) def test11_entries(self): """ Lump matrix """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) Msum = np.dot(self.ones, self.M.array().dot(self.ones)) err = abs(myobj.Mdiag.array().dot(self.ones) - \ Msum) / Msum self.assertTrue(err < 1e-14, err) def test12(self): """ Invert lumped matrix """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) err = 0.0 for ii in range(len(myobj.Mdiag.array())): err += abs(1./myobj.Mdiag[ii] - myobj.invMdiag[ii]) self.assertTrue(err < ii*1e-16) def test13_basic(self): """ solve """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) myobj.solve(self.uMdiag.vector(), myobj.Mdiag) diff = myobj.one.array() - self.uMdiag.vector().array() self.assertTrue(np.linalg.norm(diff)/np.linalg.norm(myobj.one.array()) < 1e-14) def test14_mult(self): """ overloaded * operator """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) self.uMdiag.vector().axpy(1.0, myobj*myobj.one) diff = (myobj.Mdiag - self.uMdiag.vector()).array() self.assertTrue(np.linalg.norm(diff)/np.linalg.norm(myobj.Mdiag.array()) < 1e-14)
class TestLumpedMass(unittest.TestCase): def setUp(self): mesh = UnitSquareMesh(5, 5, 'crossed') self.V = FunctionSpace(mesh, 'Lagrange', 5) self.u = Function(self.V) self.uM = Function(self.V) self.uMdiag = Function(self.V) test = TestFunction(self.V) trial = TrialFunction(self.V) m = test * trial * dx self.M = assemble(m) self.solver = LUSolver() self.solver.parameters['reuse_factorization'] = True self.solver.parameters['symmetric'] = True self.solver.set_operator(self.M) self.ones = np.ones(self.V.dim()) def test00(self): """ Create a lumped solver """ myobj = LumpedMatrixSolver(self.V) def test01_set(self): """ Set operator """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) def test01_entries(self): """ Lump matrix """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) err = 0.0 for index, ii in enumerate(self.M.array()): err += abs(ii.sum() - myobj.Mdiag[index]) self.assertTrue(err < index * 1e-16) def test02(self): """ Invert lumped matrix """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) err = 0.0 for ii in range(len(myobj.Mdiag.array())): err += abs(1. / myobj.Mdiag[ii] - myobj.invMdiag[ii]) self.assertTrue(err < ii * 1e-16) def test03_basic(self): """ solve """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) myobj.solve(self.uMdiag.vector(), myobj.Mdiag) diff = (myobj.one - self.uMdiag.vector()).array() self.assertTrue( np.linalg.norm(diff) / np.linalg.norm(myobj.one.array()) < 1e-14) def test04_mult(self): """ overloaded * operator """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) self.uMdiag.vector().axpy(1.0, myobj * myobj.one) diff = (myobj.Mdiag - self.uMdiag.vector()).array() self.assertTrue( np.linalg.norm(diff) / np.linalg.norm(myobj.Mdiag.array()) < 1e-14) def test10(self): """ Create a lumped solver """ myobj = LumpedMatrixSolverS(self.V) def test11_set(self): """ Set operator """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) def test11_entries(self): """ Lump matrix """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) Msum = np.dot(self.ones, self.M.array().dot(self.ones)) err = abs(myobj.Mdiag.array().dot(self.ones) - \ Msum) / Msum self.assertTrue(err < 1e-14, err) def test12(self): """ Invert lumped matrix """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) err = 0.0 for ii in range(len(myobj.Mdiag.array())): err += abs(1. / myobj.Mdiag[ii] - myobj.invMdiag[ii]) self.assertTrue(err < ii * 1e-16) def test13_basic(self): """ solve """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) myobj.solve(self.uMdiag.vector(), myobj.Mdiag) diff = myobj.one.array() - self.uMdiag.vector().array() self.assertTrue( np.linalg.norm(diff) / np.linalg.norm(myobj.one.array()) < 1e-14) def test14_mult(self): """ overloaded * operator """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) self.uMdiag.vector().axpy(1.0, myobj * myobj.one) diff = (myobj.Mdiag - self.uMdiag.vector()).array() self.assertTrue( np.linalg.norm(diff) / np.linalg.norm(myobj.Mdiag.array()) < 1e-14)