예제 #1
0
파일: cutmg.py 프로젝트: ngsxfem/ngsxfem
    def Mult(self,rhs,usol):            
        usol[:] = 0.

        res = usol.CreateVector()
        projres = usol.CreateVector()
        
        proj = Projector(mask=self.CutVh.FreeDofs(),range=True) 
        fnew = rhs #f.vec.data     

        projres.data = proj*fnew #f.vec
        normf = Norm(projres)

        for it in range(self.maxit):
            usol.data = self.MGpre*fnew
            res.data = fnew - self.mats[-1]*usol
            projres.data = proj*res
            res_norm = Norm(projres) / normf
            if self.printinfo:
                print("it =", it+1, " ||res||_2 =", res_norm)
            if res_norm < self.tol:
                break        

        #udraw = GridFunction( self.CutVh )
        #udraw.components[1].Set( solution[1], BND )
        #udraw.vec.data += usol.vec

        return usol
예제 #2
0
 def __init__(self,
              mat: BaseMatrix,
              pre: Optional[Preconditioner] = None,
              freedofs: Optional[BitArray] = None,
              tol: float = None,
              maxiter: int = 100,
              atol: float = None,
              callback: Optional[Callable[[int, float], None]] = None,
              callback_sol: Optional[Callable[[BaseVector], None]] = None,
              printrates: bool = False):
     super().__init__()
     if atol is None and tol is None:
         tol = 1e-12
     self.mat = mat
     assert (freedofs is None) != (pre is None
                                   )  # either pre or freedofs must be given
     self.pre = pre if pre else Projector(freedofs, True)
     self.tol = tol
     self.atol = atol
     self.maxiter = maxiter
     self.callback = callback
     self.callback_sol = callback_sol
     self.printrates = printrates
     self.residuals = []
     self.iterations = 0
예제 #3
0
    def __init__(self,
                 mat: BaseMatrix,
                 pre: Optional[Preconditioner] = None,
                 freedofs: Optional[BitArray] = None,
                 conjugate: bool = False,
                 tol: float = 1e-12,
                 maxsteps: int = 100,
                 callback: Optional[Callable[[int, float], None]] = None,
                 printing=False,
                 abstol=None):
        super().__init__()
        self.mat = mat
        assert (freedofs is None) != (pre is None
                                      )  # either pre or freedofs must be given
        self.pre = pre if pre else Projector(freedofs, True)
        self.conjugate = conjugate
        self.tol = tol
        self.abstol = abstol
        self.maxsteps = maxsteps
        self.callback = callback
        self._tmp_vecs = [self.mat.CreateRowVector() for i in range(3)]
        self.logger = logging.getLogger("CGSolver")

        self.printing = printing
        if printing:
            self.handler = handler = logging.StreamHandler()
            self.logger.addHandler(handler)
            self.logger.setLevel(logging.INFO)

        self.errors = []
        self.iterations = 0
예제 #4
0
def BVP(bf,
        lf,
        gf,
        pre=None,
        maxsteps=200,
        tol=1e-8,
        print=True,
        inverse="umfpack"):
    """
    Solve a linear boundary value problem
    """
    from ngsolve import Projector
    from ngsolve.krylovspace import CG

    r = lf.vec.CreateVector()
    r.data = lf.vec

    if bf.condense:
        r.data += bf.harmonic_extension_trans * r

        # zero local dofs
        innerbits = gf.space.FreeDofs(False) & ~gf.space.FreeDofs(True)
        Projector(innerbits, False).Project(gf.vec)

    if pre:
        CG(mat=bf.mat,
           rhs=r,
           pre=pre,
           sol=gf.vec,
           tol=tol,
           maxsteps=maxsteps,
           initialize=False,
           printrates=print)
    else:
        inv = bf.mat.Inverse(gf.space.FreeDofs(bf.condense), inverse=inverse)
        r.data -= bf.mat * gf.vec
        gf.vec.data += inv * r

    if bf.condense:
        gf.vec.data += bf.harmonic_extension * gf.vec
        gf.vec.data += bf.inner_solve * r
예제 #5
0
def PreconditionedRichardson(a,
                             rhs,
                             pre=None,
                             freedofs=None,
                             maxit=100,
                             tol=1e-8,
                             dampfactor=1.0,
                             printing=True):
    """ Preconditioned Richardson Iteration

    Parameters
    ----------
    a : BilinearForm
      The left hand side of the equation to solve

    rhs : Vector
      The right hand side of the equation.

    pre : Preconditioner
      If provided the preconditioner is used.
    
    freedofs : BitArray
      The FreeDofs on which the Richardson iteration acts. If argument is 'None' then the FreeDofs of the underlying FESpace is used.

    maxit : int
      Number of maximal iteration for Richardson iteration. If the maximal number is reached before the tolerance is reached a warning is displayed.

    tol : double
      Tolerance of the residuum. Richardson iteration stops if residuum < tolerance*initial_residuum is reached.

    dampfactor : float
      Set the damping factor for the Richardson iteration. If it is 1 then no damping is done. Values greater than 1 are allowed.

    printing : bool
      Set if Richardson iteration should print informations about the actual iteration like the residuum. 

    Returns
    -------
    (vector)
      Solution vector of the Preconditioned Richardson iteration.

    """
    u = rhs.CreateVector()
    r = rhs.CreateVector()
    u[:] = 0

    projector = Projector(
        freedofs if freedofs else a.space.FreeDofs(coupling=a.condense), False)

    r.data = rhs  # r.data = rhs - a.mat*u
    r.data -= projector * r

    it = 0
    initial_res_norm = Norm(r)
    if printing:
        print("it =", it, " ||res||_2 =", initial_res_norm)

    for it in range(1, maxit + 1):
        u.data += dampfactor * (pre * r if pre else r)
        r.data = rhs - a.mat * u
        r.data -= projector * r

        res_norm = Norm(r)
        if printing:
            print("it =", it, " ||res||_2 =", res_norm)
        if res_norm < tol * initial_res_norm:
            break
    else:
        print("Warning: Preconditioned Richardson did not converge to TOL")

    return u
예제 #6
0
파일: cutmg.py 프로젝트: ngsxfem/ngsxfem
    def Mult(self,rhs,usol):
        proj = Projector(mask=self.fes.FreeDofs(),range=True)
        usol[:] = 0.
        #
        projres = rhs.CreateVector()
        projres.data = proj*rhs
        normf = Norm(projres)
        #
        LinDof = self.linmgiter.getSpaceDim()
        
        if( type(self.fes) == ngsolve.comp.CompoundFESpace or type(self.fes) == ngsolve.comp.FESpace):
            numspaces = len( self.fes.components )
            HOdof = [ self.fes.components[i].ndof for i in range(numspaces) ]
        else:
            HOdof = [ self.fes.ndof ]
        #
        print('lindof, hdof: ')
        print(LinDof,HOdof)
        oldres = Norm(projres)

        for it in range(self.maxit):
            # initial smoothing 
            self.blockjac.Smooth(usol, rhs, self.nu)

            res = usol.CreateVector()
            # perform multiplication more efficiently ...
            # only 'upper' part (vertex dofs) needed 
            res.data = rhs -self.a.mat * usol 
            #eliminate boundary condition
            projres.data = proj*res           

            mgrhs = self.linmgiter.createVec()            
            # copy data from two domains 
            # ... should be done in combination with vertexdofs ...
            #mgrhs.Range(0, LinDof[0]).data = projres.Range(0, LinDof[0] )            
            #mgrhs.Range( LinDof[0], len(mgrhs) ).data = projres.Range(HOdof[0], HOdof[0] + LinDof[1] )
            
            mgrhs.Range(0, LinDof[0]).data = projres.Range(0, LinDof[0] )
            if( len(LinDof) > 1 ):
                offsetc = 0
                offsetf = 0
                for i in range( len(LinDof) -1 ):
                    offsetc += LinDof[i]
                    offsetf += HOdof[i]
                    mgrhs.Range( offsetc, offsetc + LinDof[i+1] ).data = projres.Range(offsetf, offsetf + LinDof[i+1] )
            
            # coarse grid correction: multigrid on linears
            cup = mgrhs.CreateVector()
            cup.data = self.linmgiter*mgrhs #maxit=1,printinfo=False)

            # update solution
            # ... should be done in combination with vertexdofs ...
            
            usol.Range(0, LinDof[0] ).data += cup.Range(0, LinDof[0])
            if( len(LinDof) > 1 ):
                offsetc = 0
                offsetf = 0
                for i in range( len(LinDof) -1 ):
                    offsetc += LinDof[i]
                    offsetf += HOdof[i]
                    usol.Range( offsetf, offsetf + LinDof[i+1] ).data += cup.Range( offsetc, offsetc + LinDof[i+1] )
            '''
            usol.Range(0, LinDof[0] ).data += cup.Range(0, LinDof[0])
            usol.Range( HOdof[0], HOdof[0] + LinDof[1]).data += cup.Range( LinDof[0], len(mgrhs) )
            '''

            # compute residual for measurement
            res.data = rhs - self.a.mat*usol
            projres.data = proj*res
            res_norm = Norm(projres)
            
            print("tg-it =", it+1, "\t ||res||_2 = {0:.2E}".format(res_norm), "\t reduction: {0:.2f}".format(res_norm/oldres))
            if res_norm < self.tol*normf:
                break
            oldres = res_norm
        
        return usol
예제 #7
0
def GMRes(A,
          b,
          pre=None,
          freedofs=None,
          x=None,
          maxsteps=100,
          tol=1e-7,
          innerproduct=None,
          callback=None,
          restart=None,
          startiteration=0,
          printrates=True):
    """ Restarting preconditioned gmres solver for A*x=b. Minimizes the preconditioned
residuum pre*(b-A*x)

Parameters
----------

A : BaseMatrix
  The left hand side of the linear system.

b : BaseVector
  The right hand side of the linear system.

pre : BaseMatrix = None
  The preconditioner for the system. If no preconditioner is given, the freedofs
  of the system must be given.

freedofs : BitArray = None
  Freedofs to solve on, only necessary if no preconditioner is given.

x : BaseVector = None
  Startvector, if given it will be modified in the routine and returned. Will be created
  if not given.

maxsteps : int = 100
  Maximum iteration steps.

tol : float = 1e-7
  Tolerance to be computed to. Gmres breaks if norm(pre*(b-A*x)) < tol.

innerproduct : function = None
  Innerproduct to be used in iteration, all orthogonalizations/norms are computed with
  respect to that inner product.

callback : function = None
  If given, this function is called with the solution vector x in each step. Only for debugging
  purposes, since it requires the overhead of computing x in every step.

restart : int = None
  If given, gmres is restarted with the current solution x every 'restart' steps.

startiteration : int = 0
  Internal value to count total number of iterations in restarted setup, no user input required
  here.

printrates : bool = True
  Print norm of preconditioned residual in each step.
"""

    if not innerproduct:
        innerproduct = lambda x, y: y.InnerProduct(x, conjugate=True)
        norm = Norm
    else:
        norm = lambda x: sqrt(innerproduct(x, x).real)
    is_complex = b.is_complex
    if not pre:
        assert freedofs is not None
        pre = Projector(freedofs, True)
    n = len(b)
    m = maxsteps
    if not x:
        x = b.CreateVector()
        x[:] = 0

    if callback:
        xstart = x.CreateVector()
        xstart.data = x
    else:
        xstart = None
    sn = Vector(m, is_complex)
    cs = Vector(m, is_complex)
    sn[:] = 0
    cs[:] = 0

    r = b.CreateVector()
    tmp = b.CreateVector()
    tmp.data = b - A * x
    r.data = pre * tmp

    Q = []
    H = []
    Q.append(b.CreateVector())
    r_norm = norm(r)
    if abs(r_norm) < tol:
        return x
    Q[0].data = 1. / r_norm * r
    beta = Vector(m + 1, is_complex)
    beta[:] = 0
    beta[0] = r_norm

    def arnoldi(A, Q, k):
        q = b.CreateVector()
        tmp.data = A * Q[k]
        q.data = pre * tmp
        h = Vector(m + 1, is_complex)
        h[:] = 0
        for i in range(k + 1):
            h[i] = innerproduct(Q[i], q)
            q.data += (-1) * h[i] * Q[i]
        h[k + 1] = norm(q)
        if abs(h[k + 1]) < 1e-12:
            return h, None
        q *= 1. / h[k + 1].real
        return h, q

    def givens_rotation(v1, v2):
        if v2 == 0:
            return 1, 0
        elif v1 == 0:
            return 0, v2 / abs(v2)
        else:
            t = sqrt((v1.conjugate() * v1 + v2.conjugate() * v2).real)
            cs = abs(v1) / t
            sn = v1 / abs(v1) * v2.conjugate() / t
            return cs, sn

    def apply_givens_rotation(h, cs, sn, k):
        for i in range(k):
            temp = cs[i] * h[i] + sn[i] * h[i + 1]
            h[i + 1] = -sn[i].conjugate() * h[i] + cs[i].conjugate() * h[i + 1]
            h[i] = temp
        cs[k], sn[k] = givens_rotation(h[k], h[k + 1])
        h[k] = cs[k] * h[k] + sn[k] * h[k + 1]
        h[k + 1] = 0

    def calcSolution(k):
        mat = Matrix(k + 1, k + 1, is_complex)
        for i in range(k + 1):
            mat[:, i] = H[i][:k + 1]
        rs = Vector(k + 1, is_complex)
        rs[:] = beta[:k + 1]
        y = mat.I * rs
        if xstart:
            x.data = xstart
        for i in range(k + 1):
            x.data += y[i] * Q[i]

    for k in range(m):
        startiteration += 1
        h, q = arnoldi(A, Q, k)
        H.append(h)
        if q is None:
            break
        Q.append(q)
        apply_givens_rotation(h, cs, sn, k)
        beta[k + 1] = -sn[k].conjugate() * beta[k]
        beta[k] = cs[k] * beta[k]
        error = abs(beta[k + 1])
        if printrates:
            print("Step", startiteration, ", error = ", error)
        if callback:
            calcSolution(k)
            callback(x)
        if error < tol:
            break
        if restart and k + 1 == restart and not (restart == maxsteps):
            calcSolution(k)
            del Q
            return GMRes(A,
                         b,
                         freedofs=freedofs,
                         pre=pre,
                         x=x,
                         maxsteps=maxsteps - restart,
                         callback=callback,
                         tol=tol,
                         innerproduct=innerproduct,
                         restart=restart,
                         startiteration=startiteration,
                         printrates=printrates)
    calcSolution(k)
    return x
예제 #8
0
파일: bvp.py 프로젝트: zhenguan1993/ngsolve
def BVP(bf, lf, gf, \
            pre=None, pre_flags={}, \
            solver=None, solver_flags={},
            maxsteps=200, tol=1e-8, print=True, inverse="umfpack",
            needsassembling=True):
    """
    Solve a linear boundary value problem A(u,v) = f(v)

Parameters
----------

bf : BilinearForm
  provides the matrix. 

lf : LinearForm
  provides the right hand side.

gf : GridFunction
  provides the solution vector

pre : Basematrix or class or string = None
  used if an iterative solver is used
  can be one of 
    * a preconditioner object
    * a preconditioner class
    * a preconditioner class name

pre_flags : dictionary = { }
  flags used to create preconditioner


    """
    from ngsolve import Projector, Preconditioner
    from ngsolve.krylovspace import CG

    if isinstance(pre, type):
        pre = pre(bf, **pre_flags)
        if not needsassembling:
            pre.Update()

    if isinstance(pre, str):
        pre = Preconditioner(bf, pre, **pre_flags)
        if not needsassembling:
            pre.Update()

    if needsassembling:
        bf.Assemble()
        lf.Assemble()

    r = lf.vec.CreateVector()
    r.data = lf.vec

    if bf.condense:
        r.data += bf.harmonic_extension_trans * r

        # zero local dofs
        innerbits = gf.space.FreeDofs(False) & ~gf.space.FreeDofs(True)
        Projector(innerbits, False).Project(gf.vec)

    if solver:
        inv = solver(mat=bf.mat, pre=pre, **solver_flags)
        r.data -= bf.mat * gf.vec
        gf.vec.data += inv * r

    elif pre:
        CG(mat=bf.mat,
           rhs=r,
           pre=pre,
           sol=gf.vec,
           tol=tol,
           maxsteps=maxsteps,
           initialize=False,
           printrates=print)
    else:
        inv = bf.mat.Inverse(gf.space.FreeDofs(bf.condense), inverse=inverse)
        r.data -= bf.mat * gf.vec
        gf.vec.data += inv * r

    if bf.condense:
        gf.vec.data += bf.harmonic_extension * gf.vec
        gf.vec.data += bf.inner_solve * r