Beispiel #1
0
    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
Beispiel #2
0
    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
Beispiel #3
0
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}"
Beispiel #4
0
    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
Beispiel #5
0
    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
Beispiel #6
0
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()
Beispiel #8
0
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()