/[escript]/trunk/escript/py_src/linearPDEs.py
ViewVC logotype

Diff of /trunk/escript/py_src/linearPDEs.py

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

revision 2337 by gross, Thu Mar 26 07:07:42 2009 UTC revision 2549 by jfenwick, Mon Jul 20 06:43:47 2009 UTC
# Line 1  Line 1 
1    
2  ########################################################  ########################################################
3  #  #
4  # Copyright (c) 2003-2008 by University of Queensland  # Copyright (c) 2003-2009 by University of Queensland
5  # Earth Systems Science Computational Center (ESSCC)  # Earth Systems Science Computational Center (ESSCC)
6  # http://www.uq.edu.au/esscc  # http://www.uq.edu.au/esscc
7  #  #
# Line 11  Line 11 
11  #  #
12  ########################################################  ########################################################
13    
14  __copyright__="""Copyright (c) 2003-2008 by University of Queensland  __copyright__="""Copyright (c) 2003-2009 by University of Queensland
15  Earth Systems Science Computational Center (ESSCC)  Earth Systems Science Computational Center (ESSCC)
16  http://www.uq.edu.au/esscc  http://www.uq.edu.au/esscc
17  Primary Business: Queensland, Australia"""  Primary Business: Queensland, Australia"""
18  __license__="""Licensed under the Open Software License version 3.0  __license__="""Licensed under the Open Software License version 3.0
19  http://www.opensource.org/licenses/osl-3.0.php"""  http://www.opensource.org/licenses/osl-3.0.php"""
20  __url__="http://www.uq.edu.au/esscc/escript-finley"  __url__="https://launchpad.net/escript-finley"
21    
22  """  """
23  The module provides an interface to define and solve linear partial  The module provides an interface to define and solve linear partial
# Line 39  by its advective terms. Line 39  by its advective terms.
39  import math  import math
40  import escript  import escript
41  import util  import util
42  import numarray  import numpy
43    
44  __author__="Lutz Gross, l.gross@uq.edu.au"  __author__="Lutz Gross, l.gross@uq.edu.au"
45    
46    
47    class SolverOptions(object):
48        """
49        this class defines the solver options for a linear or non-linear solver.
50        
51        The option also supports the handling of diagnostic informations.
52        
53        Typical usage is
54        
55        opts=SolverOptions()
56        print opts
57        opts.resetDiagnostics()
58        u=solver(opts)
59        print "number of iteration steps: =",opts.getDiagnostics("num_iter")
60        
61    
62        @cvar DEFAULT: The default method used to solve the system of linear equations
63        @cvar DIRECT: The direct solver based on LDU factorization
64        @cvar CHOLEVSKY: The direct solver based on LDLt factorization (can only be applied for symmetric PDEs)
65        @cvar PCG: The preconditioned conjugate gradient method (can only be applied for symmetric PDEs)
66        @cvar CR: The conjugate residual method
67        @cvar CGS: The conjugate gradient square method
68        @cvar BICGSTAB: The stabilized Bi-Conjugate Gradient method
69        @cvar TFQMR: Transport Free Quasi Minimal Residual method
70        @cvar MINRES: Minimum residual method
71        @cvar SSOR: The symmetric over-relaxation method
72        @cvar ILU0: The incomplete LU factorization preconditioner with no fill-in
73        @cvar ILUT: The incomplete LU factorization preconditioner with fill-in
74        @cvar JACOBI: The Jacobi preconditioner
75        @cvar GMRES: The Gram-Schmidt minimum residual method
76        @cvar PRES20: Special GMRES with restart after 20 steps and truncation after 5 residuals
77        @cvar LUMPING: Matrix lumping
78        @cvar NO_REORDERING: No matrix reordering allowed
79        @cvar MINIMUM_FILL_IN: Reorder matrix to reduce fill-in during factorization
80        @cvar NESTED_DISSECTION: Reorder matrix to improve load balancing during factorization
81        @cvar PASO: PASO solver package
82        @cvar SCSL: SGI SCSL solver library
83        @cvar MKL: Intel's MKL solver library
84        @cvar UMFPACK: The UMFPACK library
85        @cvar TRILINOS: The TRILINOS parallel solver class library from Sandia National Labs
86        @cvar ITERATIVE: The default iterative solver
87        @cvar AMG: Algebraic Multi Grid
88        @cvar REC_ILU: recursive ILU0
89        @cvar RILU: relaxed ILU0
90        @cvar GAUSS_SEIDEL: Gauss-Seidel solver
91        @cvar DEFAULT_REORDERING: the reordering method recommended by the solver
92        @cvar SUPER_LU: the Super_LU solver package
93        @cvar PASTIX: the Pastix direct solver_package
94        @cvar YAIR_SHAPIRA_COARSENING: AMG coarsening method by Yair-Shapira
95        @cvar RUGE_STUEBEN_COARSENING: AMG coarsening method by Ruge and Stueben
96        @cvar AGGREGATION_COARSENING: AMG coarsening using (symmetric) aggregation
97        @cvar MIN_COARSE_MATRIX_SIZE: minimum size of the coarsest level matrix to use direct solver.
98        @cvar NO_PRECONDITIONER: no preconditioner is applied.
99        """
100        DEFAULT= 0
101        DIRECT= 1
102        CHOLEVSKY= 2
103        PCG= 3
104        CR= 4
105        CGS= 5
106        BICGSTAB= 6
107        SSOR= 7
108        ILU0= 8
109        ILUT= 9
110        JACOBI= 10
111        GMRES= 11
112        PRES20= 12
113        LUMPING= 13
114        NO_REORDERING= 17
115        MINIMUM_FILL_IN= 18
116        NESTED_DISSECTION= 19
117        MKL= 15
118        UMFPACK= 16
119        ITERATIVE= 20
120        PASO= 21
121        AMG= 22
122        REC_ILU = 23
123        TRILINOS = 24
124        NONLINEAR_GMRES = 25
125        TFQMR = 26
126        MINRES = 27
127        GAUSS_SEIDEL=28
128        RILU=29
129        DEFAULT_REORDERING=30
130        SUPER_LU=31
131        PASTIX=32
132        YAIR_SHAPIRA_COARSENING=33
133        RUGE_STUEBEN_COARSENING=34
134        AGGREGATION_COARSENING=35
135        NO_PRECONDITIONER=36
136        MIN_COARSE_MATRIX_SIZE=37
137        
138        def __init__(self):
139            self.setLevelMax()
140            self.setCoarseningThreshold()
141            self.setNumSweeps()
142            self.setNumPreSweeps()
143            self.setNumPostSweeps()
144            self.setTolerance()
145            self.setAbsoluteTolerance()
146            self.setInnerTolerance()
147            self.setDropTolerance()
148            self.setDropStorage()
149            self.setIterMax()
150            self.setInnerIterMax()
151            self.setTruncation()
152            self.setRestart()
153            self.setSymmetry()
154            self.setVerbosity()
155            self.setInnerToleranceAdaption()
156            self.setAcceptanceConvergenceFailure()
157            self.setReordering()
158            self.setPackage()
159            self.setSolverMethod()
160            self.setPreconditioner()
161            self.setCoarsening()
162            self.setMinCoarseMatrixSize()
163            self.setRelaxationFactor()        
164            self.resetDiagnostics(all=True)
165    
166        def __str__(self):
167            return self.getSummary()
168        def getSummary(self):
169            """
170            Returns a string reporting the current settings
171            """
172            out="Solver Package: %s"%(self.getName(self.getPackage()))
173            out+="\nVerbosity = %s"%self.isVerbose()
174            out+="\nAccept failed convergence = %s"%self.acceptConvergenceFailure()
175            out+="\nRelative tolerance = %e"%self.getTolerance()
176            out+="\nAbsolute tolerance = %e"%self.getAbsoluteTolerance()
177            out+="\nSymmetric problem = %s"%self.isSymmetric()
178            out+="\nMaximum number of iteration steps = %s"%self.getIterMax()
179            out+="\nInner tolerance = %e"%self.getInnerTolerance()
180            out+="\nAdapt innner tolerance = %s"%self.adaptInnerTolerance()
181        
182            if self.getPackage() == self.PASO:
183                out+="\nSolver method = %s"%self.getName(self.getSolverMethod())
184                if self.getSolverMethod() == self.GMRES:
185                    out+="\nTruncation  = %s"%self.getTruncation()
186                    out+="\nRestart  = %s"%self.getRestart()
187                if self.getSolverMethod() == self.AMG:
188                    out+="\nNumber of pre / post sweeps = %s / %s, %s"%(self.getNumPreSweeps(), self.getNumPostSweeps(), self.getNumSweeps())
189                    out+="\nMaximum number of levels = %s"%self.LevelMax()
190                    out+="\nCoarsening threshold = %e"%self.getCoarseningThreshold()
191                    out+="\Coarsening method = %s"%self.getName(self.getCoarsening())
192                out+="\nPreconditioner = %s"%self.getName(self.getPreconditioner())
193                if self.getPreconditioner() == self.AMG:
194                    out+="\nMaximum number of levels = %s"%self.LevelMax()
195                    out+="\nCoarsening method = %s"%self.getName(self.getCoarsening())
196                    out+="\nCoarsening threshold = %e"%self.getMinCoarseMatrixSize()
197                    out+="\nMinimum size of the coarsest level matrix = %e"%self.getCoarseningThreshold()
198                    out+="\nNumber of pre / post sweeps = %s / %s, %s"%(self.getNumPreSweeps(), self.getNumPostSweeps(), self.getNumSweeps())
199                if self.getPreconditioner() == self.GAUSS_SEIDEL:
200                    out+="\nNumber of sweeps = %s"%self.getNumSweeps()
201                if self.getPreconditioner() == self.ILUT:
202                    out+="\nDrop tolerance = %e"%self.getDropTolerance()
203                    out+="\nStorage increase = %e"%self.getDropStorage()
204                if self.getPreconditioner() == self.RILU:
205                    out+="\nRelaxation factor = %e"%self.getRelaxationFactor()
206            return out
207            
208        def getName(self,key):
209            """
210            returns the name of a given key
211            
212            @param key: a valid key
213            """
214            if key == self.DEFAULT: return "DEFAULT"
215            if key == self.DIRECT: return "DIRECT"
216            if key == self.CHOLEVSKY: return "CHOLEVSKY"
217            if key == self.PCG: return "PCG"
218            if key == self.CR: return "CR"
219            if key == self.CGS: return "CGS"
220            if key == self.BICGSTAB: return "BICGSTAB"
221            if key == self.SSOR: return "SSOR"
222            if key == self.ILU0: return "ILU0:"
223            if key == self.ILUT: return "ILUT"
224            if key == self.JACOBI: return "JACOBI"
225            if key == self.GMRES: return "GMRES"
226            if key == self.PRES20: return "PRES20"
227            if key == self.LUMPING: return "LUMPING"
228            if key == self.NO_REORDERING: return "NO_REORDERING"
229            if key == self.MINIMUM_FILL_IN: return "MINIMUM_FILL_IN"
230            if key == self.NESTED_DISSECTION: return "NESTED_DISSECTION"
231            if key == self.MKL: return "MKL"
232            if key == self.UMFPACK: return "UMFPACK"
233            if key == self.ITERATIVE: return "ITERATIVE"
234            if key == self.PASO: return "PASO"
235            if key == self.AMG: return "AMG"
236            if key == self.REC_ILU: return "REC_ILU"
237            if key == self.TRILINOS: return "TRILINOS"
238            if key == self.NONLINEAR_GMRES: return "NONLINEAR_GMRES"
239            if key == self.TFQMR: return "TFQMR"
240            if key == self.MINRES: return "MINRES"
241            if key == self.GAUSS_SEIDEL: return "GAUSS_SEIDEL"
242            if key == self.RILU: return "RILU"
243            if key == self.DEFAULT_REORDERING: return "DEFAULT_REORDERING"
244            if key == self.SUPER_LU: return "SUPER_LU"
245            if key == self.PASTIX: return "PASTIX"
246            if key == self.YAIR_SHAPIRA_COARSENING: return "YAIR_SHAPIRA_COARSENING"
247            if key == self.RUGE_STUEBEN_COARSENING: return "RUGE_STUEBEN_COARSENING"
248            if key == self.AGGREGATION_COARSENING: return "AGGREGATION_COARSENING"
249            if key == self.NO_PRECONDITIONER: return "NO_PRECONDITIONER"
250            if key == self.MIN_COARSE_MATRIX_SIZE: return "MIN_COARSE_MATRIX_SIZE"
251            
252        def resetDiagnostics(self,all=False):
253            """
254            resets the diagnostics
255            
256            @param all: if C{all} is C{True} all diagnostics including accumulative counters are reset.
257            @type all: C{bool}
258            """
259            self.__num_iter=None
260            self.__num_level=None
261            self.__num_inner_iter=None
262            self.__time=None
263            self.__set_up_time=None
264            self.__residual_norm=None
265            self.__converged=None
266            if all:
267                self.__cum_num_inner_iter=0
268                self.__cum_num_iter=0
269                self.__cum_time=0
270                self.__cum_set_up_time=0
271    
272        def _updateDiagnostics(self, name, value):
273            """
274            Updates diagnostic information
275            
276            @param name: name of  diagnostic information
277            @type name: C{str} in the list "num_iter", "num_level", "num_inner_iter", "time", "set_up_time", "residual_norm", "converged".
278            @param vale: new value of the diagnostic information
279            @note: this function is used by a solver to report diagnostics informations.
280            """
281            if name == "num_iter":
282                self.__num_iter=int(value)
283                self.__cum_num_iter+=self.__num_iter
284            if name == "num_level":
285                self.__num_iter=int(value)
286            if name == "num_inner_iter":
287                self.__num_inner_iter=int(value)
288                self.__cum_num_inner_iter+=self.__num_inner_iter
289            if name == "time":
290                self.__time=float(value)
291                self.__cum_time+=self.__time
292            if name == "set_up_time":
293                self.__set_up_time=float(value)
294                self.__cum_set_up_time+=self.__set_up_time
295            if name == "residual_norm":
296                self.__residual_norm=float(value)
297            if name == "converged":
298                self.__converged = (value == True)
299        def getDiagnostics(self, name):
300            """
301            Returns the diagnostic information C{name}
302            
303            @param name: name of diagnostic information where
304            - "num_iter": the number of iteration steps
305            - "cum_num_iter": the cumulative number of iteration steps
306            - "num_level": the number of level in multi level solver
307            - "num_inner_iter": the number of inner iteration steps
308            - "cum_num_inner_iter": the cumulative number of inner iteration steps
309            - "time": execution time
310            - "cum_time": cumulative execution time
311            - "set_up_time": time to set up of the solver, typically this includes factorization and reordering
312            - "cum_set_up_time": cumulative time to set up of the solver
313            - "residual_norm": norm of the final residual
314            - "converged": return self.__converged    
315            @type name: C{str} in the list "num_iter", "num_level", "num_inner_iter", "time", "set_up_time", "residual_norm", "converged".
316            @return: requested value. C{None} is returned if the value is undefined.
317            @note: If the solver has thrown an exception diagnostic values have an undefined status.
318            """
319            if name == "num_iter": return self.__num_iter
320            elif name == "cum_num_iter": return self.__cum_num_iter
321            elif name == "num_level": return self.__num_level
322            elif name == "num_inner_iter": return self.__num_inner_iter
323            elif name == "cum_num_inner_iter": return self.__cum_num_inner_iter
324            elif name == "time": return self.__time
325            elif name == "cum_time": return self.__cum_time
326            elif name == "set_up_time": return self.__set_up_time
327            elif name == "cum_set_up_time": return self.__cum_set_up_time
328            elif name == "residual_norm": return self.__residual_norm
329            elif name == "converged": return self.__converged      
330            else:
331                raise ValueError,"unknown diagnostic item %s"%name
332        def hasConverged(self):
333            """
334            Returns C{True} if the last solver call has been finalized successfully.
335            @note: if an exception has been thrown by the solver the status of this flag is undefined.
336            """
337            return self.getDiagnostics("converged")
338        def setCoarsening(self,method=0):
339            """
340            Sets the key of the coarsening method to be applied in AMG.
341    
342            @param method: selects the coarsening method .
343            @type method: in {SolverOptions.DEFAULT}, L{SolverOptions.YAIR_SHAPIRA_COARSENING},
344            L{SolverOptions.RUGE_STUEBEN_COARSENING}, L{SolverOptions.AGGREGATION_COARSENING}
345            """
346        if method==None: method=0
347            if not method in [self.DEFAULT, self.YAIR_SHAPIRA_COARSENING, self.RUGE_STUEBEN_COARSENING, self.AGGREGATION_COARSENING]:
348                 raise ValueError,"unknown coarsening method %s"%method
349            self.__coarsening=method
350        
351        def getCoarsening(self):
352            """
353            Returns the key of the coarsening algorithm to be applied AMG.
354    
355            @rtype: in the list L{SolverOptions.DEFAULT}, L{SolverOptions.YAIR_SHAPIRA_COARSENING},
356            L{SolverOptions.RUGE_STUEBEN_COARSENING}, L{SolverOptions.AGGREGATION_COARSENING}
357            """
358            return self.__coarsening
359          
360        def setMinCoarseMatrixSize(self,size=500):
361            """
362            Sets the minumum size of the coarsest level matrix in AMG.
363    
364            @param size: minumum size of the coarsest level matrix .
365            @type size: positive C{int} or C{None}
366            """
367            size=int(size)
368            if size<0:
369               raise ValueError,"minumum size of the coarsest level matrix must be non-negative."
370        if size==None: size=500
371            self.__MinCoarseMatrixSize=size
372            
373        def getMinCoarseMatrixSize(self):
374            """
375            Returns the minumum size of the coarsest level matrix in AMG.
376    
377            @rtype: C{int}
378            """
379            return self.__MinCoarseMatrixSize
380          
381        def setPreconditioner(self, preconditioner=10):
382            """
383            Sets the preconditioner to be used.
384    
385            @param preconditioner: key of the preconditioner to be used.
386            @type preconditioner: in L{SolverOptions.SSOR}, L{SolverOptions.ILU0}, L{SolverOptions.ILUT}, L{SolverOptions.JACOBI},
387                                        L{SolverOptions.AMG}, L{SolverOptions.REC_ILU}, L{SolverOptions.GAUSS_SEIDEL}, L{SolverOptions.RILU},
388                                        L{SolverOptions.NO_PRECONDITIONER}
389            @note: Not all packages support all preconditioner. It can be assumed that a package makes a reasonable choice if it encounters
390            an unknown preconditioner.
391            """
392        if preconditioner==None: preconditioner=10
393            if not preconditioner in [ SolverOptions.SSOR, SolverOptions.ILU0, SolverOptions.ILUT, SolverOptions.JACOBI,
394                                        SolverOptions.AMG, SolverOptions.REC_ILU, SolverOptions.GAUSS_SEIDEL, SolverOptions.RILU,
395                                        SolverOptions.NO_PRECONDITIONER] :
396                 raise ValueError,"unknown preconditioner %s"%preconditioner
397            self.__preconditioner=preconditioner    
398        def getPreconditioner(self):
399            """
400            Returns key of the preconditioner to be used.
401    
402            @rtype: in the list L{SolverOptions.SSOR}, L{SolverOptions.ILU0}, L{SolverOptions.ILUT}, L{SolverOptions.JACOBI},
403                                        L{SolverOptions.AMG}, L{SolverOptions.REC_ILU}, L{SolverOptions.GAUSS_SEIDEL}, L{SolverOptions.RILU},
404                                        L{SolverOptions.NO_PRECONDITIONER}
405            """
406            return self.__preconditioner
407        def setSolverMethod(self, method=0):
408            """
409            Sets the solver method to be used. Use C{method}=C{SolverOptions.DIRECT} to indicate that a direct rather than an iterative
410            solver should be used and Use C{method}=C{SolverOptions.ITERATIVE} to indicate that an iterative rather than a direct
411            solver should be used.
412    
413            @param method: key of the solver method to be used.
414            @type method: in L{SolverOptions.DEFAULT}, L{SolverOptions.DIRECT}, L{SolverOptions.CHOLEVSKY}, L{SolverOptions.PCG},
415                            L{SolverOptions.CR}, L{SolverOptions.CGS}, L{SolverOptions.BICGSTAB}, L{SolverOptions.SSOR},
416                            L{SolverOptions.GMRES}, L{SolverOptions.PRES20}, L{SolverOptions.LUMPING}, L{SolverOptions.ITERATIVE},
417                            L{SolverOptions.AMG}, L{SolverOptions.NONLINEAR_GMRES}, L{SolverOptions.TFQMR}, L{SolverOptions.MINRES},
418                            L{SolverOptions.GAUSS_SEIDEL}
419            @note: Not all packages support all solvers. It can be assumed that a package makes a reasonable choice if it encounters
420            an unknown solver method.
421            """
422        if method==None: method=0
423            if not method in [ SolverOptions.DEFAULT, SolverOptions.DIRECT, SolverOptions.CHOLEVSKY, SolverOptions.PCG,
424                               SolverOptions.CR, SolverOptions.CGS, SolverOptions.BICGSTAB, SolverOptions.SSOR,
425                               SolverOptions.GMRES, SolverOptions.PRES20, SolverOptions.LUMPING, SolverOptions.ITERATIVE, SolverOptions.AMG,
426                               SolverOptions.NONLINEAR_GMRES, SolverOptions.TFQMR, SolverOptions.MINRES, SolverOptions.GAUSS_SEIDEL]:
427                 raise ValueError,"unknown solver method %s"%method
428            self.__method=method
429        def getSolverMethod(self):
430            """
431            Returns key of the solver method to be used.
432    
433            @rtype: in the list L{SolverOptions.DEFAULT}, L{SolverOptions.DIRECT}, L{SolverOptions.CHOLEVSKY}, L{SolverOptions.PCG},
434                            L{SolverOptions.CR}, L{SolverOptions.CGS}, L{SolverOptions.BICGSTAB}, L{SolverOptions.SSOR},
435                            L{SolverOptions.GMRES}, L{SolverOptions.PRES20}, L{SolverOptions.LUMPING}, L{SolverOptions.ITERATIVE},
436                            L{SolverOptions.AMG}, L{SolverOptions.NONLINEAR_GMRES}, L{SolverOptions.TFQMR}, L{SolverOptions.MINRES},
437                            L{SolverOptions.GAUSS_SEIDEL}
438            """
439            return self.__method
440            
441        def setPackage(self, package=0):
442            """
443            Sets the solver package to be used as a solver.  
444    
445            @param package: key of the solver package to be used.
446            @type package: in L{SolverOptions.DEFAULT}, L{SolverOptions.PASO}, L{SolverOptions.SUPER_LU}, L{SolverOptions.PASTIX}, L{SolverOptions.MKL}, L{SolverOptions.UMFPACK}, L{SolverOptions.TRILINOS}
447            @note: Not all packages are support on all implementation. An exception may be thrown on some platforms if a particular is requested.
448            """
449        if package==None: package=0
450            if not package in [SolverOptions.DEFAULT, SolverOptions.PASO, SolverOptions.SUPER_LU, SolverOptions.PASTIX, SolverOptions.MKL, SolverOptions.UMFPACK, SolverOptions.TRILINOS]:
451                 raise ValueError,"unknown solver package %s"%package
452            self.__package=package
453        def getPackage(self):
454            """
455            Returns the solver package key
456    
457            @rtype: in the list L{SolverOptions.DEFAULT}, L{SolverOptions.PASO}, L{SolverOptions.SUPER_LU}, L{SolverOptions.PASTIX}, L{SolverOptions.MKL}, L{SolverOptions.UMFPACK}, L{SolverOptions.TRILINOS}
458            """
459            return self.__package
460        def setReordering(self,ordering=30):
461            """
462            Sets the key of the reordering method to be applied if supported by the solver. Some direct solvers support reordering
463            to optimize compute time and storage use during elimination.
464    
465            @param ordering: selects the reordering strategy.
466            @type ordering: in L{SolverOptions.NO_REORDERING}, L{SolverOptions.NO_REORDERING},
467            L{SolverOptions.NO_REORDERING}, L{SolverOptions.DEFAULT_REORDERING}
468            """
469            if not ordering in [self.NO_REORDERING, self.MINIMUM_FILL_IN, self.NESTED_DISSECTION, self.DEFAULT_REORDERING]:
470                 raise ValueError,"unknown reordering strategy %s"%ordering
471            self.__reordering=ordering
472        def getReordering(self):
473            """
474            Returns the key of the reordering method to be applied if supported by the solver.
475    
476            @rtype: in the list L{SolverOptions.NO_REORDERING}, L{SolverOptions.NO_REORDERING},
477            L{SolverOptions.NO_REORDERING}, L{SolverOptions.DEFAULT_REORDERING}
478            """
479            return self.__reordering
480        def setRestart(self,restart=None):
481            """
482            Sets the number of iterations steps after which GMRES is performing a restart.
483    
484            @param restart: number of iteration steps after which to perform a restart. If equal to C{None} no
485                            restart is performed.
486            @type restart: C{int} or C{None}
487            """
488            if restart == None:
489                self.__restart=restart
490            else:
491                restart=int(restart)
492                if restart<1:
493                    raise ValueError,"restart must be positive."
494                self.__restart=restart
495            
496        def getRestart(self):
497            """
498            Returns the number of iterations steps after which GMRES is performing a restart.
499            If C{None} is returned no restart is performed.
500    
501            @rtype: C{int} or C{None}
502            """
503            if self.__restart < 0:
504                return None
505            else:
506                return self.__restart
507        def _getRestartForC(self):
508            r=self.getRestart()
509            if r == None:
510                return -1
511                else:
512                return r
513        def setTruncation(self,truncation=20):
514            """
515            Sets the number of residuals in GMRES to be stored for orthogonalization.  The more residuals are stored
516            the faster GMRES converged but
517    
518            @param truncation: truncation
519            @type truncation: C{int}
520            """
521            truncation=int(truncation)
522            if truncation<1:
523               raise ValueError,"truncation must be positive."
524            self.__truncation=truncation
525        def getTruncation(self):
526            """
527            Returns the number of residuals in GMRES to be stored for orthogonalization
528    
529            @rtype: C{int}
530            """
531            return self.__truncation
532        def setInnerIterMax(self,iter_max=10):
533            """
534            Sets the maximum number of iteration steps for the inner iteration.
535    
536            @param iter_max: maximum number of inner iterations
537            @type iter_max: C{int}
538            """
539            iter_max=int(iter_max)
540            if iter_max<1:
541               raise ValueError,"maximum number of inner iteration must be positive."
542            self.__inner_iter_max=iter_max
543        def getInnerIterMax(self):
544            """
545            Returns maximum number of inner iteration steps
546    
547            @rtype: C{int}
548            """
549            return self.__inner_iter_max
550        def setIterMax(self,iter_max=100000):
551            """
552            Sets the maximum number of iteration steps
553    
554            @param iter_max: maximum number of iteration steps
555            @type iter_max: C{int}
556            """
557            iter_max=int(iter_max)
558            if iter_max<1:
559               raise ValueError,"maximum number of iteration steps must be positive."
560            self.__iter_max=iter_max
561        def getIterMax(self):
562            """
563            Returns maximum number of iteration steps
564    
565            @rtype: C{int}
566            """
567            return self.__iter_max
568        def setLevelMax(self,level_max=10):
569            """
570            Sets the maximum number of coarsening levels to be used in an algebraic multi level solver or preconditioner
571    
572            @param level_max: maximum number of levels
573            @type level_max: C{int}
574            """
575            level_max=int(level_max)
576            if level_max<0:
577               raise ValueError,"maximum number of coarsening levels must be non-negative."
578            self.__level_max=level_max
579        def getLevelMax(self):
580            """
581            Returns the maximum number of coarsening levels to be used in an algebraic multi level solver or preconditioner
582    
583            @rtype: C{int}
584            """
585            return self.__level_max
586        def setCoarseningThreshold(self,theta=0.05):
587            """
588            Sets the threshold for coarsening in the algebraic multi level solver or preconditioner
589    
590            @param theta: threshold for coarsening
591            @type theta: positive C{float}
592            """
593            theta=float(theta)
594            if theta<0 or theta>1:
595               raise ValueError,"threshold must be non-negative and less or equal 1."
596            self.__coarsening_threshold=theta
597        def getCoarseningThreshold(self):
598            """
599            Returns the threshold for coarsening in the algebraic multi level solver or preconditioner
600    
601            @rtype: C{float}
602            """
603            return self.__coarsening_threshold
604        def setNumSweeps(self,sweeps=2):
605            """
606            Sets the number of sweeps in a Jacobi or Gauss-Seidel/SOR preconditioner.
607    
608            @param sweeps: number of sweeps
609            @type theta: positive C{int}
610            """
611            sweeps=int(sweeps)
612            if sweeps<1:
613               raise ValueError,"number of sweeps must be positive."
614            self.__sweeps=sweeps
615        def getNumSweeps(self):
616            """
617            Returns the number of sweeps in a Jacobi or Gauss-Seidel/SOR preconditioner.
618    
619            @rtype: C{int}
620            """
621            return self.__sweeps
622        def setNumPreSweeps(self,sweeps=2):
623            """
624            Sets the number of sweeps in the pre-smoothing step of a multi level solver or preconditioner
625    
626            @param sweeps: number of sweeps
627            @type theta: positive C{int}
628            """
629            sweeps=int(sweeps)
630            if sweeps<1:
631               raise ValueError,"number of sweeps must be positive."
632            self.__pre_sweeps=sweeps
633        def getNumPreSweeps(self):
634            """
635            Returns he number of sweeps in the pre-smoothing step of a multi level solver or preconditioner
636    
637            @rtype: C{int}
638            """
639            return self.__pre_sweeps
640        def setNumPostSweeps(self,sweeps=2):
641            """
642            Sets the number of sweeps in the post-smoothing step of a multi level solver or preconditioner
643    
644            @param sweeps: number of sweeps
645            @type theta: positive C{int}
646            """
647            sweeps=int(sweeps)
648            if sweeps<1:
649               raise ValueError,"number of sweeps must be positive."
650            self.__post_sweeps=sweeps
651        def getNumPostSweeps(self):
652            """
653            Returns he number of sweeps in the post-smoothing step of a multi level solver or preconditioner
654    
655            @rtype: C{int}
656            """
657            return self.__post_sweeps
658    
659        def setTolerance(self,rtol=1.e-8):
660            """
661            Sets the relative tolerance for the solver
662    
663            @param rtol: relative tolerance
664            @type rtol: non-negative C{float}
665            """
666            rtol=float(rtol)
667            if rtol<0 or rtol>1:
668               raise ValueError,"tolerance must be non-negative and less or equal 1."
669            self.__tolerance=rtol
670        def getTolerance(self):
671            """
672            Returns the relative tolerance for the solver
673    
674            @rtype: C{float}
675            """
676            return self.__tolerance
677        def setAbsoluteTolerance(self,atol=0.):
678            """
679            Sets the absolute tolerance for the solver
680    
681            @param atol:  absolute tolerance
682            @type atol: non-negative C{float}
683            """
684            atol=float(atol)
685            if atol<0:
686               raise ValueError,"tolerance must be non-negative."
687            self.__absolute_tolerance=atol
688        def getAbsoluteTolerance(self):
689            """
690            Returns the absolute tolerance for the solver
691    
692            @rtype: C{float}
693            """
694            return self.__absolute_tolerance
695    
696        def setInnerTolerance(self,rtol=0.9):
697            """
698             Sets the relative tolerance for an inner iteration scheme for instance
699            on the coarsest level in a multi-level scheme.
700    
701            @param rtol: inner relative tolerance
702            @type rtol: positive C{float}
703            """
704            rtol=float(rtol)
705            if rtol<=0 or rtol>1:
706                raise ValueError,"tolerance must be positive and less or equal 1."
707            self.__inner_tolerance=rtol
708        def getInnerTolerance(self):
709            """
710            Returns the relative tolerance for an inner iteration scheme
711    
712            @rtype: C{float}
713            """
714            return self.__inner_tolerance
715        def setDropTolerance(self,drop_tol=0.01):
716            """
717            Sets the relative drop tolerance in ILUT
718    
719            @param drop_tol: drop tolerance
720            @type drop_tol: positive C{float}
721            """
722            drop_tol=float(drop_tol)
723            if drop_tol<=0 or drop_tol>1:
724                raise ValueError,"drop tolerance must be positive and less or equal 1."
725            self.__drop_tolerance=drop_tol
726        def getDropTolerance(self):
727            """
728            Returns the relative drop tolerance in ILUT
729    
730            @rtype: C{float}
731            """
732            return self.__drop_tolerance
733        def setDropStorage(self,storage=2.):
734            """
735            Sets the maximum allowed increase in storage for ILUT. C{storage}=2 would mean that
736            a doubling of the storage needed for the coefficient matrix is allowed in the ILUT factorization.
737    
738            @param storage: allowed storage increase
739            @type storage: C{float}
740            """
741            storage=float(storage)
742            if storage<1:
743                raise ValueError,"allowed storage increase must be greater or equal to 1."
744            self.__drop_storage=storage
745        def getDropStorage(self):
746        
747            """
748            Returns the maximum allowed increase in storage for ILUT
749    
750            @rtype: C{float}
751            """
752            return self.__drop_storage
753        def setRelaxationFactor(self,factor=0.3):
754            """
755            Sets the relaxation factor used to add dropped elements in RILU to the main diagonal.
756    
757            @param factor: relaxation factor
758            @type factor: C{float}
759            @note: RILU with a relaxation factor 0 is identical to ILU0
760            """
761            factor=float(factor)
762            if factor<0:
763                raise ValueError,"relaxation factor must be non-negative."
764            self.__relaxation=factor
765        def getRelaxationFactor(self):
766        
767            """
768            Returns the relaxation factor used to add dropped elements in RILU to the main diagonal.
769    
770            @rtype: C{float}
771            """
772            return self.__relaxation
773        def isSymmetric(self):
774            """
775            Checks if symmetry of the  coefficient matrix is indicated.
776    
777            @return: True if a symmetric PDE is indicated, False otherwise
778            @rtype: C{bool}
779            """
780            return self.__symmetric
781        def setSymmetryOn(self):
782            """
783            Sets the symmetry flag to indicate that the coefficient matrix is symmetric.
784            """
785            self.__symmetric=True
786        def setSymmetryOff(self):
787            """
788            Clears the symmetry flag for the coefficient matrix.
789            """
790            self.__symmetric=False
791        def setSymmetry(self,flag=False):
792            """
793            Sets the symmetry flag for the coefficient matrix to C{flag}.
794    
795            @param flag: If True, the symmetry flag is set otherwise reset.
796            @type flag: C{bool}
797            """
798            if flag:
799                self.setSymmetryOn()
800            else:
801                self.setSymmetryOff()
802        def isVerbose(self):
803            """
804            Returns C{True} if the solver is expected to be verbose.
805    
806            @return: True if verbosity of switched on.
807            @rtype: C{bool}
808            """
809            return self.__verbose
810    
811        def setVerbosityOn(self):
812            """
813            Switches the verbosity of the solver on.
814            """
815            self.__verbose=True
816        def setVerbosityOff(self):
817            """
818            Switches the verbosity of the solver off.
819            """
820            self.__verbose=False
821        def setVerbosity(self,verbose=False):
822            """
823            Sets the verbosity flag for the solver to C{flag}.
824    
825            @param flag: If C{True}, the verbosity of the solver is switched on.
826            @type flag: C{bool}
827            """
828            if verbose:
829                self.setVerbosityOn()
830            else:
831                self.setVerbosityOff()
832            
833        def adaptInnerTolerance(self):
834            """
835            Returns C{True} if the tolerance of the inner solver is selected automatically.
836            Otherwise the inner tolerance set by L{setInnerTolerance} is used.
837    
838            @return: C{True} if inner tolerance adaption is chosen.
839            @rtype: C{bool}
840            """
841            return self.__adapt_inner_tolerance
842    
843        def setInnerToleranceAdaptionOn(self):
844            """
845            Switches the automatic selection of inner tolerance on
846            """
847            self.__adapt_inner_tolerance=True
848        def setInnerToleranceAdaptionOff(self):
849            """
850            Switches the automatic selection of inner tolerance off.
851            """
852            self.__adapt_inner_tolerance=False
853        def setInnerToleranceAdaption(self,adapt=True):
854            """
855            Sets a flag to indicate automatic selection of the inner tolerance.
856    
857            @param adapt: If C{True}, the inner tolerance is selected automatically.
858            @type adapt: C{bool}
859            """
860            if adapt:
861                self.setInnerToleranceAdaptionOn()
862            else:
863                self.setInnerToleranceAdaptionOff()
864    
865        def acceptConvergenceFailure(self):
866            """
867            Returns C{True} if a failure to meet the stopping criteria within the
868            given number of iteration steps is not raising in exception. This is useful
869            if a solver is used in a non-linear context where the non-linear solver can
870            continue even if the returned the solution does not necessarily meet the
871            stopping criteria. One can use the L{hasConverged} method to check if the
872            last call to the solver was successful.
873    
874            @return: C{True} if a failure to achieve convergence is accepted.
875            @rtype: C{bool}
876            """
877            return self.__accept_convergence_failure
878    
879        def setAcceptanceConvergenceFailureOn(self):
880            """
881            Switches the acceptance of a failure of convergence on
882            """
883            self.__accept_convergence_failure=True
884        def setAcceptanceConvergenceFailureOff(self):
885            """
886            Switches the acceptance of a failure of convergence off.
887            """
888            self.__accept_convergence_failure=False
889        def setAcceptanceConvergenceFailure(self,accept=False):
890            """
891            Sets a flag to indicate the acceptance of a failure of convergence.
892    
893            @param accept: If C{True}, any failure to achieve convergence is accepted.
894            @type accept: C{bool}
895            """
896            if accept:
897                self.setAcceptanceConvergenceFailureOn()
898            else:
899                self.setAcceptanceConvergenceFailureOff()
900    
901  class IllegalCoefficient(ValueError):  class IllegalCoefficient(ValueError):
902     """     """
903     Exception that is raised if an illegal coefficient of the general or     Exception that is raised if an illegal coefficient of the general or
# Line 379  class PDECoef(object): Line 1233  class PDECoef(object):
1233                  s=s+(dim,)                  s=s+(dim,)
1234         return s         return s
1235    
1236    #====================================================================================================================
1237    
1238  class LinearProblem(object):  class LinearProblem(object):
1239     """     """
1240     This is the base class to define a general linear PDE-type problem for     This is the base class to define a general linear PDE-type problem for
# Line 394  class LinearProblem(object): Line 1250  class LinearProblem(object):
1250     where M{L} is an operator and M{f} is the right hand side. This operator     where M{L} is an operator and M{f} is the right hand side. This operator
1251     problem will be solved to get the unknown M{u}.     problem will be solved to get the unknown M{u}.
1252    
1253     @cvar DEFAULT: The default method used to solve the system of linear     """
                   equations  
    @cvar DIRECT: The direct solver based on LDU factorization  
    @cvar CHOLEVSKY: The direct solver based on LDLt factorization (can only be  
                     applied for symmetric PDEs)  
    @cvar PCG: The preconditioned conjugate gradient method (can only be applied  
               for symmetric PDEs)  
    @cvar CR: The conjugate residual method  
    @cvar CGS: The conjugate gradient square method  
    @cvar BICGSTAB: The stabilized BiConjugate Gradient method  
    @cvar TFQMR: Transport Free Quasi Minimal Residual method  
    @cvar MINRES: Minimum residual method  
    @cvar SSOR: The symmetric overrelaxation method  
    @cvar ILU0: The incomplete LU factorization preconditioner with no fill-in  
    @cvar ILUT: The incomplete LU factorization preconditioner with fill-in  
    @cvar JACOBI: The Jacobi preconditioner  
    @cvar GMRES: The Gram-Schmidt minimum residual method  
    @cvar PRES20: Special GMRES with restart after 20 steps and truncation after  
                  5 residuals  
    @cvar LUMPING: Matrix lumping  
    @cvar NO_REORDERING: No matrix reordering allowed  
    @cvar MINIMUM_FILL_IN: Reorder matrix to reduce fill-in during factorization  
    @cvar NESTED_DISSECTION: Reorder matrix to improve load balancing during  
                             factorization  
    @cvar PASO: PASO solver package  
    @cvar SCSL: SGI SCSL solver library  
    @cvar MKL: Intel's MKL solver library  
    @cvar UMFPACK: The UMFPACK library  
    @cvar TRILINOS: The TRILINOS parallel solver class library from Sandia Natl  
                    Labs  
    @cvar ITERATIVE: The default iterative solver  
    @cvar AMG: Algebraic Multi Grid  
    @cvar RILU: Recursive ILU  
    @cvar GS: Gauss-Seidel solver  
   
    """  
    DEFAULT= 0  
    DIRECT= 1  
    CHOLEVSKY= 2  
    PCG= 3  
    CR= 4  
    CGS= 5  
    BICGSTAB= 6  
    SSOR= 7  
    ILU0= 8  
    ILUT= 9  
    JACOBI= 10  
    GMRES= 11  
    PRES20= 12  
    LUMPING= 13  
    NO_REORDERING= 17  
    MINIMUM_FILL_IN= 18  
    NESTED_DISSECTION= 19  
    SCSL= 14  
    MKL= 15  
    UMFPACK= 16  
    ITERATIVE= 20  
    PASO= 21  
    AMG= 22  
    RILU = 23  
    TRILINOS = 24  
    NONLINEAR_GMRES = 25  
    TFQMR = 26  
    MINRES = 27  
    GS=28  
   
    SMALL_TOLERANCE=1.e-13  
    PACKAGE_KEY="package"  
    METHOD_KEY="method"  
    SYMMETRY_KEY="symmetric"  
    TOLERANCE_KEY="tolerance"  
    PRECONDITIONER_KEY="preconditioner"  
   
   
1254     def __init__(self,domain,numEquations=None,numSolutions=None,debug=False):     def __init__(self,domain,numEquations=None,numSolutions=None,debug=False):
1255       """       """
1256       Initializes a linear problem.       Initializes a linear problem.
# Line 491  class LinearProblem(object): Line 1274  class LinearProblem(object):
1274       self.__altered_coefficients=False       self.__altered_coefficients=False
1275       self.__reduce_equation_order=False       self.__reduce_equation_order=False
1276       self.__reduce_solution_order=False       self.__reduce_solution_order=False
1277       self.__tolerance=1.e-8       self.__sym=False
1278       self.__solver_method=self.DEFAULT       self.setSolverOptions()
      self.__solver_package=self.DEFAULT  
      self.__preconditioner=self.DEFAULT  
1279       self.__is_RHS_valid=False       self.__is_RHS_valid=False
1280       self.__is_operator_valid=False       self.__is_operator_valid=False
      self.__sym=False  
1281       self.__COEFFICIENTS={}       self.__COEFFICIENTS={}
1282         self.__solution_rtol=1.e99
1283         self.__solution_atol=1.e99
1284         self.setSymmetryOff()
1285       # initialize things:       # initialize things:
1286       self.resetAllCoefficients()       self.resetAllCoefficients()
1287       self.__system_type=None       self.initializeSystem()
      self.updateSystemType()  
1288     # ==========================================================================     # ==========================================================================
1289     #    general stuff:     #    general stuff:
1290     # ==========================================================================     # ==========================================================================
# Line 578  class LinearProblem(object): Line 1360  class LinearProblem(object):
1360       @rtype: L{Domain<escript.Domain>}       @rtype: L{Domain<escript.Domain>}
1361       """       """
1362       return self.__domain       return self.__domain
1363       def getDomainStatus(self):
1364         """
1365         Return the status indicator of the domain
1366         """
1367         return self.getDomain().getStatus()
1368    
1369       def getSystemStatus(self):
1370         """
1371         Return the domain status used to build the current system
1372         """
1373         return self.__system_status
1374       def setSystemStatus(self,status=None):
1375         """
1376         Sets the system status to C{status} if C{status} is not present the
1377         current status of the domain is used.
1378         """
1379         if status == None:
1380             self.__system_status=self.getDomainStatus()
1381         else:
1382             self.__system_status=status
1383    
1384     def getDim(self):     def getDim(self):
1385       """       """
# Line 667  class LinearProblem(object): Line 1469  class LinearProblem(object):
1469     # ==========================================================================     # ==========================================================================
1470     #   solver settings:     #   solver settings:
1471     # ==========================================================================     # ==========================================================================
1472     def setSolverMethod(self,solver=None,preconditioner=None):     def setSolverOptions(self,options=None):
        """  
        Sets a new solver method and/or preconditioner.  
   
        @param solver: new solver method to use  
        @type solver: one of L{DEFAULT}, L{ITERATIVE} L{DIRECT}, L{CHOLEVSKY},  
                      L{PCG}, L{CR}, L{CGS}, L{BICGSTAB}, L{SSOR}, L{GMRES},  
                      L{TFQMR}, L{MINRES}, L{PRES20}, L{LUMPING}, L{AMG}  
        @param preconditioner: new preconditioner to use  
        @type preconditioner: one of L{DEFAULT}, L{JACOBI} L{ILU0}, L{ILUT},  
                              L{SSOR}, L{RILU}, L{GS}  
   
        @note: the solver method chosen may not be available by the selected  
               package.  
        """  
        if solver==None: solver=self.__solver_method  
        if preconditioner==None: preconditioner=self.__preconditioner  
        if solver==None: solver=self.DEFAULT  
        if preconditioner==None: preconditioner=self.DEFAULT  
        if not (solver,preconditioner)==self.getSolverMethod():  
            self.__solver_method=solver  
            self.__preconditioner=preconditioner  
            self.updateSystemType()  
            self.trace("New solver is %s"%self.getSolverMethodName())  
   
    def getSolverMethodName(self):  
        """  
        Returns the name of the solver currently used.  
   
        @return: the name of the solver currently used  
        @rtype: C{string}  
        """  
   
        m=self.getSolverMethod()  
        p=self.getSolverPackage()  
        method=""  
        if m[0]==self.DEFAULT: method="DEFAULT"  
        elif m[0]==self.DIRECT: method= "DIRECT"  
        elif m[0]==self.ITERATIVE: method= "ITERATIVE"  
        elif m[0]==self.CHOLEVSKY: method= "CHOLEVSKY"  
        elif m[0]==self.PCG: method= "PCG"  
        elif m[0]==self.TFQMR: method= "TFQMR"  
        elif m[0]==self.MINRES: method= "MINRES"  
        elif m[0]==self.CR: method= "CR"  
        elif m[0]==self.CGS: method= "CGS"  
        elif m[0]==self.BICGSTAB: method= "BICGSTAB"  
        elif m[0]==self.SSOR: method= "SSOR"  
        elif m[0]==self.GMRES: method= "GMRES"  
        elif m[0]==self.PRES20: method= "PRES20"  
        elif m[0]==self.LUMPING: method= "LUMPING"  
        elif m[0]==self.AMG: method= "AMG"  
        if m[1]==self.DEFAULT: method+="+DEFAULT"  
        elif m[1]==self.JACOBI: method+= "+JACOBI"  
        elif m[1]==self.ILU0: method+= "+ILU0"  
        elif m[1]==self.ILUT: method+= "+ILUT"  
        elif m[1]==self.SSOR: method+= "+SSOR"  
        elif m[1]==self.AMG: method+= "+AMG"  
        elif m[1]==self.RILU: method+= "+RILU"  
        elif m[1]==self.GS: method+= "+GS"  
        if p==self.DEFAULT: package="DEFAULT"  
        elif p==self.PASO: package= "PASO"  
        elif p==self.MKL: package= "MKL"  
        elif p==self.SCSL: package= "SCSL"  
        elif p==self.UMFPACK: package= "UMFPACK"  
        elif p==self.TRILINOS: package= "TRILINOS"  
        else : method="unknown"  
        return "%s solver of %s package"%(method,package)  
   
    def getSolverMethod(self):  
        """  
        Returns the solver method and preconditioner used.  
   
        @return: the solver method currently used.  
        @rtype: C{tuple} of C{int}  
        """  
        return self.__solver_method,self.__preconditioner  
   
    def setSolverPackage(self,package=None):  
        """  
        Sets a new solver package.  
   
        @param package: the new solver package  
        @type package: one of L{DEFAULT}, L{PASO} L{SCSL}, L{MKL}, L{UMFPACK},  
                       L{TRILINOS}  
        """  
        if package==None: package=self.DEFAULT  
        if not package==self.getSolverPackage():  
            self.__solver_package=package  
            self.updateSystemType()  
            self.trace("New solver is %s"%self.getSolverMethodName())  
   
    def getSolverPackage(self):  
        """  
        Returns the package of the solver.  
   
        @return: the solver package currently being used  
        @rtype: C{int}  
1473         """         """
1474         return self.__solver_package         Sets the solver options.
1475    
1476           @param options: the new solver options. If equal C{None}, the solver options are set to the default.
1477           @type options: L{SolverOptions} or C{None}
1478           @note: The symmetry flag of options is overwritten by the symmetry flag of the L{LinearProblem}.
1479           """
1480           if options==None:
1481              self.__solver_options=SolverOptions()
1482           elif isinstance(options, SolverOptions):
1483              self.__solver_options=options
1484           else:
1485              raise ValueError,"options must be a SolverOptions object."
1486           self.__solver_options.setSymmetry(self.__sym)
1487        
1488       def getSolverOptions(self):
1489           """
1490           Returns the solver options
1491      
1492           @rtype: L{SolverOptions}
1493           """
1494           self.__solver_options.setSymmetry(self.__sym)
1495           return self.__solver_options
1496          
1497     def isUsingLumping(self):     def isUsingLumping(self):
1498        """        """
1499        Checks if matrix lumping is the current solver method.        Checks if matrix lumping is the current solver method.
# Line 774  class LinearProblem(object): Line 1501  class LinearProblem(object):
1501        @return: True if the current solver method is lumping        @return: True if the current solver method is lumping
1502        @rtype: C{bool}        @rtype: C{bool}
1503        """        """
1504        return self.getSolverMethod()[0]==self.LUMPING        return self.getSolverOptions().getSolverMethod()==self.getSolverOptions().LUMPING
   
    def setTolerance(self,tol=1.e-8):  
        """  
        Resets the tolerance for the solver method to C{tol}.  
   
        @param tol: new tolerance for the solver. If C{tol} is lower than the  
                    current tolerence the system will be resolved.  
        @type tol: positive C{float}  
        @raise ValueError: if tolerance is not positive  
        """  
        if not tol>0:  
            raise ValueError,"Tolerance has to be positive"  
        if tol<self.getTolerance(): self.invalidateSolution()  
        self.trace("New tolerance %e"%tol)  
        self.__tolerance=tol  
        return  
   
    def getTolerance(self):  
        """  
        Returns the tolerance currently set for the solution.  
   
        @return: tolerance currently used  
        @rtype: C{float}  
        """  
        return self.__tolerance  
   
1505     # ==========================================================================     # ==========================================================================
1506     #    symmetry  flag:     #    symmetry  flag:
1507     # ==========================================================================     # ==========================================================================
# Line 810  class LinearProblem(object): Line 1511  class LinearProblem(object):
1511    
1512        @return: True if a symmetric PDE is indicated, False otherwise        @return: True if a symmetric PDE is indicated, False otherwise
1513        @rtype: C{bool}        @rtype: C{bool}
1514          @note: the method is equivalent to use getSolverOptions().isSymmetric()
1515        """        """
1516        return self.__sym        self.getSolverOptions().isSymmetric()
1517    
1518     def setSymmetryOn(self):     def setSymmetryOn(self):
1519        """        """
1520        Sets the symmetry flag.        Sets the symmetry flag.
1521          @note: The method overwrites the symmetry flag set by the solver options
1522        """        """
1523        if not self.isSymmetric():        self.__sym=True
1524           self.trace("PDE is set to be symmetric")        self.getSolverOptions().setSymmetryOn()
          self.__sym=True  
          self.updateSystemType()  
1525    
1526     def setSymmetryOff(self):     def setSymmetryOff(self):
1527        """        """
1528        Clears the symmetry flag.        Clears the symmetry flag.
1529          @note: The method overwrites the symmetry flag set by the solver options
1530        """        """
1531        if self.isSymmetric():        self.__sym=False
1532           self.trace("PDE is set to be nonsymmetric")        self.getSolverOptions().setSymmetryOff()
          self.__sym=False  
          self.updateSystemType()  
1533    
1534     def setSymmetryTo(self,flag=False):     def setSymmetry(self,flag=False):
1535        """        """
1536        Sets the symmetry flag to C{flag}.        Sets the symmetry flag to C{flag}.
1537    
1538        @param flag: If True, the symmetry flag is set otherwise reset.        @param flag: If True, the symmetry flag is set otherwise reset.
1539        @type flag: C{bool}        @type flag: C{bool}
1540          @note: The method overwrites the symmetry flag set by the solver options
1541        """        """
1542        if flag:        self.getSolverOptions().setSymmetry(flag)
          self.setSymmetryOn()  
       else:  
          self.setSymmetryOff()  
   
1543     # ==========================================================================     # ==========================================================================
1544     # function space handling for the equation as well as the solution     # function space handling for the equation as well as the solution
1545     # ==========================================================================     # ==========================================================================
# Line 969  class LinearProblem(object): Line 1666  class LinearProblem(object):
1666          self.setReducedOrderForEquationOn()          self.setReducedOrderForEquationOn()
1667       else:       else:
1668          self.setReducedOrderForEquationOff()          self.setReducedOrderForEquationOff()
1669       def getOperatorType(self):
    def updateSystemType(self):  
      """  
      Reassesses the system type and, if a new matrix is needed, resets the  
      system.  
      """  
      new_system_type=self.getRequiredSystemType()  
      if not new_system_type==self.__system_type:  
          self.trace("Matrix type is now %d."%new_system_type)  
          self.__system_type=new_system_type  
          self.initializeSystem()  
   
    def getSystemType(self):  
1670        """        """
1671        Returns the current system type.        Returns the current system type.
1672        """        """
1673        return self.__system_type        return self.__operator_type
1674    
1675     def checkSymmetricTensor(self,name,verbose=True):     def checkSymmetricTensor(self,name,verbose=True):
1676        """        """
# Line 999  class LinearProblem(object): Line 1684  class LinearProblem(object):
1684        @return: True if coefficient C{name} is symmetric        @return: True if coefficient C{name} is symmetric
1685        @rtype: C{bool}        @rtype: C{bool}
1686        """        """
1687          SMALL_TOLERANCE=util.EPSILON*10.
1688        A=self.getCoefficient(name)        A=self.getCoefficient(name)
1689        verbose=verbose or self.__debug        verbose=verbose or self.__debug
1690        out=True        out=True
1691        if not A.isEmpty():        if not A.isEmpty():
1692           tol=util.Lsup(A)*self.SMALL_TOLERANCE           tol=util.Lsup(A)*SMALL_TOLERANCE
1693           s=A.getShape()           s=A.getShape()
1694           if A.getRank() == 4:           if A.getRank() == 4:
1695              if s[0]==s[2] and s[1] == s[3]:              if s[0]==s[2] and s[1] == s[3]:
# Line 1048  class LinearProblem(object): Line 1734  class LinearProblem(object):
1734                 symmetric.                 symmetric.
1735        @rtype: C{bool}        @rtype: C{bool}
1736        """        """
1737          SMALL_TOLERANCE=util.EPSILON*10.
1738        B=self.getCoefficient(name0)        B=self.getCoefficient(name0)
1739        C=self.getCoefficient(name1)        C=self.getCoefficient(name1)
1740        verbose=verbose or self.__debug        verbose=verbose or self.__debug
# Line 1061  class LinearProblem(object): Line 1748  class LinearProblem(object):
1748        elif not B.isEmpty() and not C.isEmpty():        elif not B.isEmpty() and not C.isEmpty():
1749           sB=B.getShape()           sB=B.getShape()
1750           sC=C.getShape()           sC=C.getShape()
1751           tol=(util.Lsup(B)+util.Lsup(C))*self.SMALL_TOLERANCE/2.           tol=(util.Lsup(B)+util.Lsup(C))*SMALL_TOLERANCE/2.
1752           if len(sB) != len(sC):           if len(sB) != len(sC):
1753               if verbose: print "non-symmetric problem because ranks of %s (=%s) and %s (=%s) are different."%(name0,len(sB),name1,len(sC))               if verbose: print "non-symmetric problem because ranks of %s (=%s) and %s (=%s) are different."%(name0,len(sB),name1,len(sC))
1754               out=False               out=False
# Line 1206  class LinearProblem(object): Line 1893  class LinearProblem(object):
1893         """         """
1894         Returns True if the solution is still valid.         Returns True if the solution is still valid.
1895         """         """
1896           if not self.getDomainStatus()==self.getSystemStatus(): self.invalidateSolution()
1897           if self.__solution_rtol>self.getSolverOptions().getTolerance() or \
1898              self.__solution_atol>self.getSolverOptions().getAbsoluteTolerance():
1899             self.invalidateSolution()  
1900         return self.__is_solution_valid         return self.__is_solution_valid
1901    
1902     def validOperator(self):     def validOperator(self):
# Line 1226  class LinearProblem(object): Line 1917  class LinearProblem(object):
1917         """         """
1918         Returns True if the operator is still valid.         Returns True if the operator is still valid.
1919         """         """
1920           if not self.getDomainStatus()==self.getSystemStatus(): self.invalidateOperator()
1921           if not self.getRequiredOperatorType()==self.getOperatorType(): self.invalidateOperator()
1922         return self.__is_operator_valid         return self.__is_operator_valid
1923    
1924     def validRightHandSide(self):     def validRightHandSide(self):
# Line 1238  class LinearProblem(object): Line 1931  class LinearProblem(object):
1931         """         """
1932         Indicates the right hand side has to be rebuilt next time it is used.         Indicates the right hand side has to be rebuilt next time it is used.
1933         """         """
1934         if self.isRightHandSideValid(): self.trace("Right hand side has to be rebuilt.")         self.trace("Right hand side has to be rebuilt.")
1935         self.invalidateSolution()         self.invalidateSolution()
1936         self.__is_RHS_valid=False         self.__is_RHS_valid=False
1937    
# Line 1246  class LinearProblem(object): Line 1939  class LinearProblem(object):
1939         """         """
1940         Returns True if the operator is still valid.         Returns True if the operator is still valid.
1941         """         """
1942           if not self.getDomainStatus()==self.getSystemStatus(): self.invalidateRightHandSide()
1943         return self.__is_RHS_valid         return self.__is_RHS_valid
1944    
1945     def invalidateSystem(self):     def invalidateSystem(self):
1946         """         """
1947         Announces that everything has to be rebuilt.         Announces that everything has to be rebuilt.
1948         """         """
        if self.isRightHandSideValid(): self.trace("System has to be rebuilt.")  
1949         self.invalidateSolution()         self.invalidateSolution()
1950         self.invalidateOperator()         self.invalidateOperator()
1951         self.invalidateRightHandSide()         self.invalidateRightHandSide()
# Line 1268  class LinearProblem(object): Line 1961  class LinearProblem(object):
1961         Resets the system clearing the operator, right hand side and solution.         Resets the system clearing the operator, right hand side and solution.
1962         """         """
1963         self.trace("New System has been created.")         self.trace("New System has been created.")
1964           self.__operator_type=None
1965           self.setSystemStatus()
1966         self.__operator=escript.Operator()         self.__operator=escript.Operator()
1967         self.__righthandside=escript.Data()         self.__righthandside=escript.Data()
1968         self.__solution=escript.Data()         self.__solution=escript.Data()
# Line 1322  class LinearProblem(object): Line 2017  class LinearProblem(object):
2017    
2018     def setSolution(self,u):     def setSolution(self,u):
2019         """         """
2020         Sets the solution assuming that makes the system valid.         Sets the solution assuming that makes the system valid with the tolrance
2021           defined by the solver options
2022         """         """
2023           self.__solution_rtol=self.getSolverOptions().getTolerance()
2024           self.__solution_atol=self.getSolverOptions().getAbsoluteTolerance()
2025         self.__solution=u         self.__solution=u
2026         self.validSolution()         self.validSolution()
2027    
# Line 1356  class LinearProblem(object): Line 2054  class LinearProblem(object):
2054         Makes sure that the operator is instantiated and returns it initialized         Makes sure that the operator is instantiated and returns it initialized
2055         with zeros.         with zeros.
2056         """         """
2057         if self.__operator.isEmpty():         if self.getOperatorType() == None:
2058             if self.isUsingLumping():             if self.isUsingLumping():
2059                 self.__operator=self.createSolution()                 self.__operator=self.createSolution()
2060             else:             else:
2061                 self.__operator=self.createOperator()                 self.__operator=self.createOperator()
2062           self.__operator_type=self.getRequiredOperatorType()
2063         else:         else:
2064             if self.isUsingLumping():             if self.isUsingLumping():
2065                 self.__operator.setToZero()                 self.__operator.setToZero()
# Line 1372  class LinearProblem(object): Line 2071  class LinearProblem(object):
2071         """         """
2072         Returns the operator in its current state.         Returns the operator in its current state.
2073         """         """
        if self.__operator.isEmpty(): self.resetOperator()  
2074         return self.__operator         return self.__operator
2075    
2076     def setValue(self,**coefficients):     def setValue(self,**coefficients):
# Line 1393  class LinearProblem(object): Line 2091  class LinearProblem(object):
2091              elif hasattr(d,"getShape"):              elif hasattr(d,"getShape"):
2092                  s=d.getShape()                  s=d.getShape()
2093              else:              else:
2094                  s=numarray.array(d).shape                  s=numpy.array(d).shape
2095              if s!=None:              if s!=None:
2096                  # get number of equations and number of unknowns:                  # get number of equations and number of unknowns:
2097                  res=self.__COEFFICIENTS[i].estimateNumEquationsAndNumSolutions(self.getDomain(),s)                  res=self.__COEFFICIENTS[i].estimateNumEquationsAndNumSolutions(self.getDomain(),s)
# Line 1434  class LinearProblem(object): Line 2132  class LinearProblem(object):
2132     # methods that are typically overwritten when implementing a particular     # methods that are typically overwritten when implementing a particular
2133     # linear problem     # linear problem
2134     # ==========================================================================     # ==========================================================================
2135     def getRequiredSystemType(self):     def getRequiredOperatorType(self):
2136        """        """
2137        Returns the system type which needs to be used by the current set up.        Returns the system type which needs to be used by the current set up.
2138    
2139        @note: Typically this method is overwritten when implementing a        @note: Typically this method is overwritten when implementing a
2140               particular linear problem.               particular linear problem.
2141        """        """
2142        return 0        return None
2143    
2144     def createOperator(self):     def createOperator(self):
2145         """         """
# Line 1490  class LinearProblem(object): Line 2188  class LinearProblem(object):
2188                linear problem.                linear problem.
2189         """         """
2190         return (self.getCurrentOperator(), self.getCurrentRightHandSide())         return (self.getCurrentOperator(), self.getCurrentRightHandSide())
 #=====================  
2191    
2192  class LinearPDE(LinearProblem):  class LinearPDE(LinearProblem):
2193     """     """
# Line 1675  class LinearPDE(LinearProblem): Line 2372  class LinearPDE(LinearProblem):
2372       """       """
2373       return "<LinearPDE %d>"%id(self)       return "<LinearPDE %d>"%id(self)
2374    
2375     def getRequiredSystemType(self):     def getRequiredOperatorType(self):
2376        """        """
2377        Returns the system type which needs to be used by the current set up.        Returns the system type which needs to be used by the current set up.
2378        """        """
2379        return self.getDomain().getSystemMatrixTypeId(self.getSolverMethod()[0],self.getSolverMethod()[1],self.getSolverPackage(),self.isSymmetric())        solver_options=self.getSolverOptions()
2380          return self.getDomain().getSystemMatrixTypeId(solver_options.getSolverMethod(), solver_options.getPreconditioner(),solver_options.getPackage(), solver_options.isSymmetric())
2381    
2382     def checkSymmetry(self,verbose=True):     def checkSymmetry(self,verbose=True):
2383        """        """
# Line 1710  class LinearPDE(LinearProblem): Line 2408  class LinearPDE(LinearProblem):
2408         """         """
2409         Returns an instance of a new operator.         Returns an instance of a new operator.
2410         """         """
2411         self.trace("New operator is allocated.")         optype=self.getRequiredOperatorType()
2412           self.trace("New operator of type %s is allocated."%optype)
2413         return self.getDomain().newOperator( \         return self.getDomain().newOperator( \
2414                             self.getNumEquations(), \                             self.getNumEquations(), \
2415                             self.getFunctionSpaceForEquation(), \                             self.getFunctionSpaceForEquation(), \
2416                             self.getNumSolutions(), \                             self.getNumSolutions(), \
2417                             self.getFunctionSpaceForSolution(), \                             self.getFunctionSpaceForSolution(), \
2418                             self.getSystemType())                             optype)
2419    
2420     def getSolution(self,**options):     def getSolution(self):
2421         """         """
2422         Returns the solution of the PDE.         Returns the solution of the PDE.
2423    
2424         @return: the solution         @return: the solution
2425         @rtype: L{Data<escript.Data>}         @rtype: L{Data<escript.Data>}
        @param options: solver options  
        @keyword verbose: True to get some information during PDE solution  
        @type verbose: C{bool}  
        @keyword reordering: reordering scheme to be used during elimination.  
                             Allowed values are L{NO_REORDERING},  
                             L{MINIMUM_FILL_IN} and L{NESTED_DISSECTION}  
        @keyword iter_max: maximum number of iteration steps allowed  
        @keyword drop_tolerance: threshold for dropping in L{ILUT}  
        @keyword drop_storage: maximum of allowed memory in L{ILUT}  
        @keyword truncation: maximum number of residuals in L{GMRES}  
        @keyword restart: restart cycle length in L{GMRES}  
2426         """         """
2427           option_class=self.getSolverOptions()
2428         if not self.isSolutionValid():         if not self.isSolutionValid():
2429            mat,f=self.getSystem()            mat,f=self.getSystem()
2430            if self.isUsingLumping():            if self.isUsingLumping():
2431               self.setSolution(f*1/mat)               self.setSolution(f*1/mat)
2432            else:            else:
              options[self.TOLERANCE_KEY]=self.getTolerance()  
              options[self.METHOD_KEY]=self.getSolverMethod()[0]  
              options[self.PRECONDITIONER_KEY]=self.getSolverMethod()[1]  
              options[self.PACKAGE_KEY]=self.getSolverPackage()  
              options[self.SYMMETRY_KEY]=self.isSymmetric()  
2433               self.trace("PDE is resolved.")               self.trace("PDE is resolved.")
2434               self.trace("solver options: %s"%str(options))               self.trace("solver options: %s"%str(option_class))
2435               self.setSolution(mat.solve(f,options))               self.setSolution(mat.solve(f,option_class))
2436         return self.getCurrentSolution()         return self.getCurrentSolution()
2437    
2438     def getSystem(self):     def getSystem(self):
# Line 1786  class LinearPDE(LinearProblem): Line 2470  class LinearPDE(LinearProblem):
2470                   d_reduced=self.getCoefficient("d_reduced")                   d_reduced=self.getCoefficient("d_reduced")
2471                   if not D.isEmpty():                   if not D.isEmpty():
2472                       if self.getNumSolutions()>1:                       if self.getNumSolutions()>1:
2473                          D_times_e=util.matrix_mult(D,numarray.ones((self.getNumSolutions(),)))                          D_times_e=util.matrix_mult(D,numpy.ones((self.getNumSolutions(),)))
2474                       else:                       else:
2475                          D_times_e=D                          D_times_e=D
2476                   else:                   else:
2477                      D_times_e=escript.Data()                      D_times_e=escript.Data()
2478                   if not d.isEmpty():                   if not d.isEmpty():
2479                       if self.getNumSolutions()>1:                       if self.getNumSolutions()>1:
2480                          d_times_e=util.matrix_mult(d,numarray.ones((self.getNumSolutions(),)))                          d_times_e=util.matrix_mult(d,numpy.ones((self.getNumSolutions(),)))
2481                       else:                       else:
2482                          d_times_e=d                          d_times_e=d
2483                   else:                   else:
# Line 1801  class LinearPDE(LinearProblem): Line 2485  class LinearPDE(LinearProblem):
2485    
2486                   if not D_reduced.isEmpty():                   if not D_reduced.isEmpty():
2487                       if self.getNumSolutions()>1:                       if self.getNumSolutions()>1:
2488                          D_reduced_times_e=util.matrix_mult(D_reduced,numarray.ones((self.getNumSolutions(),)))                          D_reduced_times_e=util.matrix_mult(D_reduced,numpy.ones((self.getNumSolutions(),)))
2489                       else:                       else:
2490                          D_reduced_times_e=D_reduced                          D_reduced_times_e=D_reduced
2491                   else:                   else:
2492                      D_reduced_times_e=escript.Data()                      D_reduced_times_e=escript.Data()
2493                   if not d_reduced.isEmpty():                   if not d_reduced.isEmpty():
2494                       if self.getNumSolutions()>1:                       if self.getNumSolutions()>1:
2495                          d_reduced_times_e=util.matrix_mult(d_reduced,numarray.ones((self.getNumSolutions(),)))                          d_reduced_times_e=util.matrix_mult(d_reduced,numpy.ones((self.getNumSolutions(),)))
2496                       else:                       else:
2497                          d_reduced_times_e=d_reduced                          d_reduced_times_e=d_reduced
2498                   else:                   else:
# Line 1924  class LinearPDE(LinearProblem): Line 2608  class LinearPDE(LinearProblem):
2608                   self.insertConstraint(rhs_only=False)                   self.insertConstraint(rhs_only=False)
2609                   self.trace("New operator has been built.")                   self.trace("New operator has been built.")
2610                   self.validOperator()                   self.validOperator()
2611           self.setSystemStatus()
2612           self.trace("System status is %s."%self.getSystemStatus())
2613         return (self.getCurrentOperator(), self.getCurrentRightHandSide())         return (self.getCurrentOperator(), self.getCurrentRightHandSide())
2614    
2615     def insertConstraint(self, rhs_only=False):     def insertConstraint(self, rhs_only=False):
# Line 2240  class Helmholtz(LinearPDE): Line 2926  class Helmholtz(LinearPDE):
2926       """       """
2927       if name == "A" :       if name == "A" :
2928           if self.getCoefficient("k").isEmpty():           if self.getCoefficient("k").isEmpty():
2929                return escript.Data(numarray.identity(self.getDim()),escript.Function(self.getDomain()))                return escript.Data(numpy.identity(self.getDim()),escript.Function(self.getDomain()))
2930           else:           else:
2931                return escript.Data(numarray.identity(self.getDim()),escript.Function(self.getDomain()))*self.getCoefficient("k")                return escript.Data(numpy.identity(self.getDim()),escript.Function(self.getDomain()))*self.getCoefficient("k")
2932       elif name == "D" :       elif name == "D" :
2933           return self.getCoefficient("omega")           return self.getCoefficient("omega")
2934       elif name == "Y" :       elif name == "Y" :
# Line 2721  class TransportPDE(LinearProblem): Line 3407  class TransportPDE(LinearProblem):
3407           theta=1.           theta=1.
3408         else:         else:
3409           theta=0.5           theta=0.5
3410           optype=self.getRequiredOperatorType()
3411         self.trace("New Transport problem is allocated.")         self.trace("New Transport problem pf type %s is allocated."%optype)
3412         return self.getDomain().newTransportProblem( \         return self.getDomain().newTransportProblem( \
3413                                 theta,                                 theta,
3414                                 self.getNumEquations(), \                                 self.getNumEquations(), \
3415                                 self.getFunctionSpaceForSolution(), \                                 self.getFunctionSpaceForSolution(), \
3416                                 self.getSystemType())                                 optype)
3417    
3418     def setInitialSolution(self,u):     def setInitialSolution(self,u):
3419         """         """
# Line 2747  class TransportPDE(LinearProblem): Line 3433  class TransportPDE(LinearProblem):
3433                raise ValueError,"Illegal shape %s of initial solution."%(u2.getShape(),)                raise ValueError,"Illegal shape %s of initial solution."%(u2.getShape(),)
3434         self.getOperator().setInitialValue(u2)         self.getOperator().setInitialValue(u2)
3435    
3436     def getRequiredSystemType(self):     def getRequiredOperatorType(self):
3437        """        """
3438        Returns the system type which needs to be used by the current set up.        Returns the system type which needs to be used by the current set up.
3439    
3440        @return: a code to indicate the type of transport problem scheme used        @return: a code to indicate the type of transport problem scheme used
3441        @rtype: C{float}        @rtype: C{float}
3442        """        """
3443        return self.getDomain().getTransportTypeId(self.getSolverMethod()[0],self.getSolverMethod()[1],self.getSolverPackage(),self.isSymmetric())        solver_options=self.getSolverOptions()
3444          return self.getDomain().getTransportTypeId(solver_options.getSolverMethod(), solver_options.getPreconditioner(),solver_options.getPackage(), solver_options.isSymmetric())
3445    
3446     def getUnlimitedTimeStepSize(self):     def getUnlimitedTimeStepSize(self):
3447        """        """
# Line 2799  class TransportPDE(LinearProblem): Line 3486  class TransportPDE(LinearProblem):
3486         """         """
3487         return self.__constraint_factor         return self.__constraint_factor
3488     #====================================================================     #====================================================================
3489     def getSolution(self,dt,**options):     def getSolution(self,dt):
3490         """         """
3491         Returns the solution of the problem.         Returns the solution of the problem.
3492    
3493         @return: the solution         @return: the solution
3494         @rtype: L{Data<escript.Data>}         @rtype: L{Data<escript.Data>}
   
3495         """         """
3496           option_class=self.getSolverOptions()
3497         if dt<=0:         if dt<=0:
3498             raise ValueError,"step size needs to be positive."             raise ValueError,"step size needs to be positive."
3499         options[self.TOLERANCE_KEY]=self.getTolerance()         self.setSolution(self.getOperator().solve(self.getRightHandSide(),dt,option_class))
        self.setSolution(self.getOperator().solve(self.getRightHandSide(),dt,options))  
3500         self.validSolution()         self.validSolution()
3501         return self.getCurrentSolution()         return self.getCurrentSolution()
3502    
# Line 2860  class TransportPDE(LinearProblem): Line 3546  class TransportPDE(LinearProblem):
3546            self.trace("New system has been built.")            self.trace("New system has been built.")
3547            self.validOperator()            self.validOperator()
3548            self.validRightHandSide()            self.validRightHandSide()
3549           self.setSystemStatus()
3550           self.trace("System status is %s."%self.getSystemStatus())
3551         return (self.getCurrentOperator(), self.getCurrentRightHandSide())         return (self.getCurrentOperator(), self.getCurrentRightHandSide())
3552    
3553       def setDebug(self, flag):
3554         """
3555         Switches debug output on if C{flag} is True,
3556         otherwise it is switched off.
3557    
3558         @param flag: desired debug status
3559         @type flag: C{bool}
3560         """
3561         if flag:
3562             self.setDebugOn()
3563         else:
3564             self.setDebugOff()
3565    
3566       def setDebugOn(self):
3567         """
3568         Switches debug output on.
3569         """
3570         super(TransportPDE,self).setDebugOn()
3571        
3572       def setDebugOff(self):
3573         """
3574         Switches debug output off.
3575         """
3576         super(TransportPDE,self).setDebugOff()
3577        

Legend:
Removed from v.2337  
changed lines
  Added in v.2549

  ViewVC Help
Powered by ViewVC 1.1.26