/[escript]/temp/escript/py_src/pdetools.py
ViewVC logotype

Diff of /temp/escript/py_src/pdetools.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 867 by gross, Mon Oct 9 06:50:09 2006 UTC revision 1312 by ksteube, Mon Sep 24 06:18:44 2007 UTC
# Line 1  Line 1 
1    #
2  # $Id$  # $Id$
3    #
4    #######################################################
5    #
6    #           Copyright 2003-2007 by ACceSS MNRF
7    #       Copyright 2007 by University of Queensland
8    #
9    #                http://esscc.uq.edu.au
10    #        Primary Business: Queensland, Australia
11    #  Licensed under the Open Software License version 3.0
12    #     http://www.opensource.org/licenses/osl-3.0.php
13    #
14    #######################################################
15    #
16    
17  """  """
18  Provides some tools related to PDEs.  Provides some tools related to PDEs.
# Line 32  import escript Line 46  import escript
46  import linearPDEs  import linearPDEs
47  import numarray  import numarray
48  import util  import util
49    import math
50    
51  class TimeIntegrationManager:  class TimeIntegrationManager:
52    """    """
# Line 132  class Projector: Line 147  class Projector:
147      self.__pde.setValue(D = 1.)      self.__pde.setValue(D = 1.)
148      return      return
149    
   def __del__(self):  
     return  
   
150    def __call__(self, input_data):    def __call__(self, input_data):
151      """      """
152      Projects input_data onto a continuous function      Projects input_data onto a continuous function
# Line 142  class Projector: Line 154  class Projector:
154      @param input_data: The input_data to be projected.      @param input_data: The input_data to be projected.
155      """      """
156      out=escript.Data(0.,input_data.getShape(),self.__pde.getFunctionSpaceForSolution())      out=escript.Data(0.,input_data.getShape(),self.__pde.getFunctionSpaceForSolution())
157        self.__pde.setValue(Y = escript.Data(), Y_reduced = escript.Data())
158      if input_data.getRank()==0:      if input_data.getRank()==0:
159          self.__pde.setValue(Y = input_data)          self.__pde.setValue(Y = input_data)
160          out=self.__pde.getSolution()          out=self.__pde.getSolution()
# Line 297  class Locator: Line 310  class Locator:
310         Initializes a Locator to access values in Data objects on the Doamin         Initializes a Locator to access values in Data objects on the Doamin
311         or FunctionSpace where for the sample point which         or FunctionSpace where for the sample point which
312         closest to the given point x.         closest to the given point x.
313    
314           @param where: function space
315           @type where: L{escript.FunctionSpace}
316           @param x: coefficient of the solution.
317           @type x: L{numarray.NumArray} or C{list} of L{numarray.NumArray}
318         """         """
319         if isinstance(where,escript.FunctionSpace):         if isinstance(where,escript.FunctionSpace):
320            self.__function_space=where            self.__function_space=where
321         else:         else:
322            self.__function_space=escript.ContinuousFunction(where)            self.__function_space=escript.ContinuousFunction(where)
323         self.__id=util.length(self.__function_space.getX()-x[:self.__function_space.getDim()]).mindp()         if isinstance(x, list):
324               self.__id=[]
325               for p in x:
326                  self.__id.append(util.length(self.__function_space.getX()-p[:self.__function_space.getDim()]).minGlobalDataPoint())
327           else:
328               self.__id=util.length(self.__function_space.getX()-x[:self.__function_space.getDim()]).minGlobalDataPoint()
329    
330       def __str__(self):       def __str__(self):
331         """         """
332         Returns the coordinates of the Locator as a string.         Returns the coordinates of the Locator as a string.
333         """         """
334         return "<Locator %s>"%str(self.getX())         x=self.getX()
335           if instance(x,list):
336              out="["
337              first=True
338              for xx in x:
339                if not first:
340                    out+=","
341                else:
342                    first=False
343                out+=str(xx)
344              out+="]>"
345           else:
346              out=str(x)
347           return out
348    
349         def getX(self):
350            """
351        Returns the exact coordinates of the Locator.
352        """
353            return self(self.getFunctionSpace().getX())
354    
355       def getFunctionSpace(self):       def getFunctionSpace(self):
356          """          """
# Line 316  class Locator: Line 358  class Locator:
358      """      """
359          return self.__function_space          return self.__function_space
360    
361       def getId(self):       def getId(self,item=None):
362          """          """
363      Returns the identifier of the location.      Returns the identifier of the location.
364      """      """
365          return self.__id          if item == None:
366               return self.__id
367            else:
368               if isinstance(self.__id,list):
369                  return self.__id[item]
370               else:
371                  return self.__id
372    
      def getX(self):  
         """  
     Returns the exact coordinates of the Locator.  
     """  
         return self(self.getFunctionSpace().getX())  
373    
374       def __call__(self,data):       def __call__(self,data):
375          """          """
# Line 342  class Locator: Line 385  class Locator:
385      """      """
386          if isinstance(data,escript.Data):          if isinstance(data,escript.Data):
387             if data.getFunctionSpace()==self.getFunctionSpace():             if data.getFunctionSpace()==self.getFunctionSpace():
388               #out=data.convertToNumArrayFromDPNo(self.getId()[0],self.getId()[1])               dat=data
              out=data.convertToNumArrayFromDPNo(self.getId()[0],self.getId()[1],self.getId()[2])  
389             else:             else:
390               #out=data.interpolate(self.getFunctionSpace()).convertToNumArrayFromDPNo(self.getId()[0],self.getId()[1])               dat=data.interpolate(self.getFunctionSpace())
391               out=data.interpolate(self.getFunctionSpace()).convertToNumArrayFromDPNo(self.getId()[0],self.getId()[1],self.getId()[2])             id=self.getId()
392             if data.getRank()==0:             r=data.getRank()
393                return out[0]             if isinstance(id,list):
394                   out=[]
395                   for i in id:
396                      o=data.getValueOfGlobalDataPoint(*i)
397                      if data.getRank()==0:
398                         out.append(o[0])
399                      else:
400                         out.append(o)
401                   return out
402             else:             else:
403                return out               out=data.getValueOfGlobalDataPoint(*id)
404                 if data.getRank()==0:
405                    return out[0]
406                 else:
407                    return out
408          else:          else:
409             return data             return data
410    
411    class SolverSchemeException(Exception):
412       """
413       exceptions thrown by solvers
414       """
415       pass
416    
417    class IndefinitePreconditioner(SolverSchemeException):
418       """
419       the preconditioner is not positive definite.
420       """
421       pass
422    class MaxIterReached(SolverSchemeException):
423       """
424       maxium number of iteration steps is reached.
425       """
426       pass
427    class IterationBreakDown(SolverSchemeException):
428       """
429       iteration scheme econouters an incurable breakdown.
430       """
431       pass
432    class NegativeNorm(SolverSchemeException):
433       """
434       a norm calculation returns a negative norm.
435       """
436       pass
437    
438    def PCG(b,x,Aprod,Msolve,bilinearform, norm, verbose=True, iter_max=100, tolerance=math.sqrt(util.EPSILON)):
439       """
440       Solver for
441    
442       M{Ax=b}
443    
444       with a symmetric and positive definite operator A (more details required!).
445       It uses the conjugate gradient method with preconditioner M providing an approximation of A.
446    
447       The iteration is terminated if
448    
449       M{norm(r) <= tolerance * norm(b)}
450    
451       where C{norm()} defines a norm and
452    
453       M{r = b-Ax}
454    
455       the residual.
456    
457       For details on the preconditioned conjugate gradient method see the book:
458    
459       Templates for the Solution of Linear Systems by R. Barrett, M. Berry,
460       T.F. Chan, J. Demmel, J. Donato, J. Dongarra, V. Eijkhout, R. Pozo,
461       C. Romine, and H. van der Vorst.
462    
463       @param b: the right hand side of the liner system. C{b} is altered.
464       @type b: any object type R supporting inplace add (x+=y) and scaling (x=scalar*y)
465       @param x: an initial guess for the solution
466       @type x: any object type S supporting inplace add (x+=y), scaling (x=scalar*y)
467       @param Aprod: returns the value Ax
468       @type Aprod: function C{Aprod(x)} where C{x} is of object type S. The returned object needs to be of type R.
469       @param Msolve: solves Mx=r
470       @type Msolve: function C{Msolve(r)} where C{r} is of object type R. The returned object needs to be of tupe S.
471       @param bilinearform: inner product C{<x,r>}
472       @type bilinearform: function C{bilinearform(x,r)} where C{x} is of object type S and C{r} is of object type R. The returned value is a C{float}.
473       @param norm: norm calculation for the residual C{r=b-Ax}.
474       @type norm: function C{norm(r)} where C{r} is of object type R. The returned value is a C{float}.
475       @param verbose: switches on the printing out some information
476       @type verbose: C{bool}
477       @param iter_max: maximum number of iteration steps.
478       @type iter_max: C{int}
479       @param tolerance: tolerance
480       @type tolerance: positive C{float}
481       @return: the solution apprximation and the corresponding residual
482       @rtype: C{tuple} of an S type and and an R type object.A
483       @warning: C{b} ans C{x} are altered.
484       """
485       if verbose:
486            print "Enter PCG for solving Ax=b\n\t iter_max =%s\t tolerance   =%e"%(iter_max,tolerance)
487       iter=0
488       normb = norm(b)
489       if normb<0: raise NegativeNorm
490    
491       b += (-1)*Aprod(x)
492       r=b
493       rhat=Msolve(r)
494       d = rhat;
495       rhat_dot_r = bilinearform(rhat, r)
496    
497       while True:
498           normr=norm(r)
499           if normr<0: raise NegativeNorm
500           if verbose: print "iter: %s: norm(r) = %e, tolerance*norm(b) = %e"%(iter, normr,tolerance * normb)
501           if normr <= tolerance * normb: return x,r
502    
503           iter+=1 # k = iter = 1 first time through
504           if iter  >= iter_max: raise MaxIterReached,"maximum number of %s steps reached."%iter_max
505    
506           q=Aprod(d)
507           alpha = rhat_dot_r / bilinearform(d, q)
508           x += alpha * d
509           r += (-alpha) * q
510    
511           rhat=Msolve(r)
512           rhat_dot_r_new = bilinearform(rhat, r)
513           beta = rhat_dot_r_new / rhat_dot_r
514           rhat+=beta * d
515           d=rhat
516    
517           rhat_dot_r = rhat_dot_r_new
518    
519    
520  class SaddlePointProblem(object):  class SaddlePointProblem(object):
521     """     """
522     This implements a solver for a saddlepoint problem     This implements a solver for a saddlepoint problem
523    
524     f(u,p)=0     M{f(u,p)=0}
525     g(u)=0     M{g(u)=0}
526    
527     for u and p. The problem is solved with an inexact Uszawa scheme for p:     for u and p. The problem is solved with an inexact Uszawa scheme for p:
528    
529     Q_f (u^{k+1}-u^{k}) = - f(u^{k},p^{k})     M{Q_f (u^{k+1}-u^{k}) = - f(u^{k},p^{k})}
530     Q_g (p^{k+1}-p^{k}) =   g(u^{k+1})     M{Q_g (p^{k+1}-p^{k}) =   g(u^{k+1})}
531    
532     where Q_f is an approximation of the Jacobiean A_f of f with respect to u  and Q_f is an approximation of     where Q_f is an approximation of the Jacobiean A_f of f with respect to u  and Q_f is an approximation of
533     A_g A_f^{-1} A_g with A_g is the jacobiean of g with respect to p. As a the construction of a 'proper'     A_g A_f^{-1} A_g with A_g is the jacobiean of g with respect to p. As a the construction of a 'proper'
# Line 375  class SaddlePointProblem(object): Line 538  class SaddlePointProblem(object):
538         """         """
539         initializes the problem         initializes the problem
540    
541         @parm verbose: switches on the printing out some information         @param verbose: switches on the printing out some information
542         @type verbose: C{bool}         @type verbose: C{bool}
543         @note: this method may be overwritten by a particular saddle point problem         @note: this method may be overwritten by a particular saddle point problem
544         """         """
545           if not isinstance(verbose,bool):
546                raise TypeError("verbose needs to be of type bool.")
547         self.__verbose=verbose         self.__verbose=verbose
548           self.relaxation=1.
549    
550     def trace(self,text):     def trace(self,text):
551         """         """
552         prints text if verbose has been set         prints text if verbose has been set
553    
554         @parm text: a text message         @param text: a text message
555         @type text: C{str}         @type text: C{str}
556         """         """
557         if self.__verbose: print "%s: %s"%(str(self),text)         if self.__verbose: print "%s: %s"%(str(self),text)
558    
559     def solve_f(self,u,p,tol=1.e-7,*args):     def solve_f(self,u,p,tol=1.e-8):
560         """         """
561         solves         solves
562    
# Line 402  class SaddlePointProblem(object): Line 568  class SaddlePointProblem(object):
568         @type u: L{escript.Data}         @type u: L{escript.Data}
569         @param p: current approximation of p         @param p: current approximation of p
570         @type p: L{escript.Data}         @type p: L{escript.Data}
571         @param tol: tolerance for du         @param tol: tolerance expected for du
572         @type tol: C{float}         @type tol: C{float}
573         @return: increment du         @return: increment du
574         @rtype: L{escript.Data}         @rtype: L{escript.Data}
# Line 410  class SaddlePointProblem(object): Line 576  class SaddlePointProblem(object):
576         """         """
577         pass         pass
578    
579     def solve_g(self,u,*args):     def solve_g(self,u,tol=1.e-8):
580         """         """
581         solves         solves
582    
# Line 420  class SaddlePointProblem(object): Line 586  class SaddlePointProblem(object):
586    
587         @param u: current approximation of u         @param u: current approximation of u
588         @type u: L{escript.Data}         @type u: L{escript.Data}
589           @param tol: tolerance expected for dp
590           @type tol: C{float}
591         @return: increment dp         @return: increment dp
592         @rtype: L{escript.Data}         @rtype: L{escript.Data}
593         @note: this method has to be overwritten by a particular saddle point problem         @note: this method has to be overwritten by a particular saddle point problem
# Line 434  class SaddlePointProblem(object): Line 602  class SaddlePointProblem(object):
602         """         """
603         pass         pass
604    
605     def solve(self,u0,p0,tolerance=1.e-6,*args):     subiter_max=3
606         pass     def solve(self,u0,p0,tolerance=1.e-6,tolerance_u=None,iter_max=100,accepted_reduction=0.995,relaxation=None):
607  # vim: expandtab shiftwidth=4:          """
608            runs the solver
609    
610            @param u0: initial guess for C{u}
611            @type u0: L{esys.escript.Data}
612            @param p0: initial guess for C{p}
613            @type p0: L{esys.escript.Data}
614            @param tolerance: tolerance for relative error in C{u} and C{p}
615            @type tolerance: positive C{float}
616            @param tolerance_u: tolerance for relative error in C{u} if different from C{tolerance}
617            @type tolerance_u: positive C{float}
618            @param iter_max: maximum number of iteration steps.
619            @type iter_max: C{int}
620            @param accepted_reduction: if the norm  g cannot be reduced by C{accepted_reduction} backtracking to adapt the
621                                       relaxation factor. If C{accepted_reduction=None} no backtracking is used.
622            @type accepted_reduction: positive C{float} or C{None}
623            @param relaxation: initial relaxation factor. If C{relaxation==None}, the last relaxation factor is used.
624            @type relaxation: C{float} or C{None}
625            """
626            tol=1.e-2
627            if tolerance_u==None: tolerance_u=tolerance
628            if not relaxation==None: self.relaxation=relaxation
629            if accepted_reduction ==None:
630                  angle_limit=0.
631            elif accepted_reduction>=1.:
632                  angle_limit=0.
633            else:
634                  angle_limit=util.sqrt(1-accepted_reduction**2)
635            self.iter=0
636            u=u0
637            p=p0
638            #
639            #   initialize things:
640            #
641            converged=False
642            #
643            #  start loop:
644            #
645            #  initial search direction is g
646            #
647            while not converged :
648                if self.iter>iter_max:
649                    raise ArithmeticError("no convergence after %s steps."%self.iter)
650                f_new=self.solve_f(u,p,tol)
651                norm_f_new = util.Lsup(f_new)
652                u_new=u-f_new
653                g_new=self.solve_g(u_new,tol)
654                self.iter+=1
655                norm_g_new = util.sqrt(self.inner(g_new,g_new))
656                if norm_f_new==0. and norm_g_new==0.: return u, p
657                if self.iter>1 and not accepted_reduction==None:
658                   #
659                   #   did we manage to reduce the norm of G? I
660                   #   if not we start a backtracking procedure
661                   #
662                   # print "new/old norm = ",norm_g_new, norm_g, norm_g_new/norm_g
663                   if norm_g_new > accepted_reduction * norm_g:
664                      sub_iter=0
665                      s=self.relaxation
666                      d=g
667                      g_last=g
668                      self.trace("    start substepping: f = %s, g = %s, relaxation = %s."%(norm_f_new, norm_g_new, s))
669                      while sub_iter < self.subiter_max and  norm_g_new > accepted_reduction * norm_g:
670                         dg= g_new-g_last
671                         norm_dg=abs(util.sqrt(self.inner(dg,dg))/self.relaxation)
672                         rad=self.inner(g_new,dg)/self.relaxation
673                         # print "   ",sub_iter,": rad, norm_dg:",abs(rad), norm_dg*norm_g_new * angle_limit
674                         # print "   ",sub_iter,": rad, norm_dg:",rad, norm_dg, norm_g_new, norm_g
675                         if abs(rad) < norm_dg*norm_g_new * angle_limit:
676                             if sub_iter>0: self.trace("    no further improvements expected from backtracking.")
677                             break
678                         r=self.relaxation
679                         self.relaxation= - rad/norm_dg**2
680                         s+=self.relaxation
681                         #####
682                         # a=g_new+self.relaxation*dg/r
683                         # print "predicted new norm = ",util.sqrt(self.inner(a,a)),util.sqrt(self.inner(g_new,g_new)), self.relaxation
684                         #####
685                         g_last=g_new
686                         p+=self.relaxation*d
687                         f_new=self.solve_f(u,p,tol)
688                         u_new=u-f_new
689                         g_new=self.solve_g(u_new,tol)
690                         self.iter+=1
691                         norm_f_new = util.Lsup(f_new)
692                         norm_g_new = util.sqrt(self.inner(g_new,g_new))
693                         # print "   ",sub_iter," new g norm",norm_g_new
694                         self.trace("    %s th sub-step: f = %s, g = %s, relaxation = %s."%(sub_iter, norm_f_new, norm_g_new, s))
695                         #
696                         #   can we expect reduction of g?
697                         #
698                         # u_last=u_new
699                         sub_iter+=1
700                      self.relaxation=s
701                #
702                #  check for convergence:
703                #
704                norm_u_new = util.Lsup(u_new)
705                p_new=p+self.relaxation*g_new
706                norm_p_new = util.sqrt(self.inner(p_new,p_new))
707                self.trace("%s th step: f = %s, f/u = %s, g = %s, g/p = %s, relaxation = %s."%(self.iter, norm_f_new ,norm_f_new/norm_u_new, norm_g_new, norm_g_new/norm_p_new, self.relaxation))
708    
709                if self.iter>1:
710                   dg2=g_new-g
711                   df2=f_new-f
712                   norm_dg2=util.sqrt(self.inner(dg2,dg2))
713                   norm_df2=util.Lsup(df2)
714                   # print norm_g_new, norm_g, norm_dg, norm_p, tolerance
715                   tol_eq_g=tolerance*norm_dg2/(norm_g*abs(self.relaxation))*norm_p_new
716                   tol_eq_f=tolerance_u*norm_df2/norm_f*norm_u_new
717                   if norm_g_new <= tol_eq_g and norm_f_new <= tol_eq_f:
718                       converged=True
719                f, norm_f, u, norm_u, g, norm_g, p, norm_p = f_new, norm_f_new, u_new, norm_u_new, g_new, norm_g_new, p_new, norm_p_new
720            self.trace("convergence after %s steps."%self.iter)
721            return u,p
722    #   def solve(self,u0,p0,tolerance=1.e-6,iter_max=10,self.relaxation=1.):
723    #      tol=1.e-2
724    #      iter=0
725    #      converged=False
726    #      u=u0*1.
727    #      p=p0*1.
728    #      while not converged and iter<iter_max:
729    #          du=self.solve_f(u,p,tol)
730    #          u-=du
731    #          norm_du=util.Lsup(du)
732    #          norm_u=util.Lsup(u)
733    #        
734    #          dp=self.relaxation*self.solve_g(u,tol)
735    #          p+=dp
736    #          norm_dp=util.sqrt(self.inner(dp,dp))
737    #          norm_p=util.sqrt(self.inner(p,p))
738    #          print iter,"-th step rel. errror u,p= (%s,%s) (%s,%s)(%s,%s)"%(norm_du,norm_dp,norm_du/norm_u,norm_dp/norm_p,norm_u,norm_p)
739    #          iter+=1
740    #
741    #          converged = (norm_du <= tolerance*norm_u) and  (norm_dp <= tolerance*norm_p)
742    #      if converged:
743    #          print "convergence after %s steps."%iter
744    #      else:
745    #          raise ArithmeticError("no convergence after %s steps."%iter)
746    #
747    #      return u,p
748              
749    def MaskFromBoundaryTag(function_space,*tags):
750       """
751       create a mask on the given function space which one for samples
752       that touch the boundary tagged by tags.
753    
754       usage: m=MaskFromBoundaryTag(Solution(domain),"left", "right")
755    
756       @param function_space: a given function space
757       @type function_space: L{escript.FunctionSpace}
758       @param tags: boundray tags
759       @type tags: C{str}
760       @return: a mask which marks samples used by C{function_space} that are touching the
761                boundary tagged by any of the given tags.
762       @rtype: L{escript.Data} of rank 0
763       """
764       pde=linearPDEs.LinearPDE(function_space.getDomain(),numEquations=1, numSolutions=1)
765       d=escript.Scalar(0.,escript.FunctionOnBoundary(function_space.getDomain()))
766       for t in tags: d.setTaggedValue(t,1.)
767       pde.setValue(y=d)
768       out=util.whereNonZero(pde.getRightHandSide())
769       if out.getFunctionSpace() == function_space:
770          return out
771       else:
772          return util.whereNonZero(util.interpolate(out,function_space))
773    

Legend:
Removed from v.867  
changed lines
  Added in v.1312

  ViewVC Help
Powered by ViewVC 1.1.26