172 |
out+="\nAbsolute tolerance = %e"%self.getAbsoluteTolerance() |
out+="\nAbsolute tolerance = %e"%self.getAbsoluteTolerance() |
173 |
out+="\nSymmetric problem = %s"%self.isSymmetric() |
out+="\nSymmetric problem = %s"%self.isSymmetric() |
174 |
out+="\nMaximum number of iteration steps = %s"%self.getIterMax() |
out+="\nMaximum number of iteration steps = %s"%self.getIterMax() |
175 |
|
out+="\nInner tolerance = %e"%self.getInnerTolerance() |
176 |
|
out+="\nAdapt innner tolerance = %s"%self.adaptInnerTolerance() |
177 |
|
|
178 |
if self.getPackage() == self.PASO: |
if self.getPackage() == self.PASO: |
179 |
out+="\nSolver method = %s"%self.getName(self.getSolverMethod()) |
out+="\nSolver method = %s"%self.getName(self.getSolverMethod()) |
180 |
if self.getSolverMethod() == self.GMRES: |
if self.getSolverMethod() == self.GMRES: |
334 |
Sets the key of the coarsening method to be applied in AMG. |
Sets the key of the coarsening method to be applied in AMG. |
335 |
|
|
336 |
@param method: selects the coarsening method . |
@param method: selects the coarsening method . |
337 |
@type method: in L{SolverOptions.DEFAULT}, L{SolverOptions.YAIR_SHAPIRA_COARSENING}, |
@type method: in {SolverOptions.DEFAULT}, L{SolverOptions.YAIR_SHAPIRA_COARSENING}, |
338 |
L{SolverOptions.RUGE_STUEBEN_COARSENING}, L{SolverOptions.AGGREGATION_COARSENING} |
L{SolverOptions.RUGE_STUEBEN_COARSENING}, L{SolverOptions.AGGREGATION_COARSENING} |
339 |
""" |
""" |
340 |
|
if method==None: method=0 |
341 |
if not method in [self.DEFAULT, self.YAIR_SHAPIRA_COARSENING, self.RUGE_STUEBEN_COARSENING, self.AGGREGATION_COARSENING]: |
if not method in [self.DEFAULT, self.YAIR_SHAPIRA_COARSENING, self.RUGE_STUEBEN_COARSENING, self.AGGREGATION_COARSENING]: |
342 |
raise ValueError,"unknown coarsening method %s"%method |
raise ValueError,"unknown coarsening method %s"%method |
343 |
self.__coarsening=method |
self.__coarsening=method |
360 |
@note: Not all packages support all preconditioner. It can be assumed that a package makes a reasonable choice if it encounters |
@note: Not all packages support all preconditioner. It can be assumed that a package makes a reasonable choice if it encounters |
361 |
an unknown preconditioner. |
an unknown preconditioner. |
362 |
""" |
""" |
363 |
|
if preconditioner==None: preconditioner=10 |
364 |
if not preconditioner in [ SolverOptions.SSOR, SolverOptions.ILU0, SolverOptions.ILUT, SolverOptions.JACOBI, |
if not preconditioner in [ SolverOptions.SSOR, SolverOptions.ILU0, SolverOptions.ILUT, SolverOptions.JACOBI, |
365 |
SolverOptions.AMG, SolverOptions.REC_ILU, SolverOptions.GAUSS_SEIDEL, SolverOptions.RILU, |
SolverOptions.AMG, SolverOptions.REC_ILU, SolverOptions.GAUSS_SEIDEL, SolverOptions.RILU, |
366 |
SolverOptions.NO_PRECONDITIONER] : |
SolverOptions.NO_PRECONDITIONER] : |
390 |
@note: Not all packages support all solvers. It can be assumed that a package makes a reasonable choice if it encounters |
@note: Not all packages support all solvers. It can be assumed that a package makes a reasonable choice if it encounters |
391 |
an unknown solver method. |
an unknown solver method. |
392 |
""" |
""" |
393 |
|
if method==None: method=0 |
394 |
if not method in [ SolverOptions.DEFAULT, SolverOptions.DIRECT, SolverOptions.CHOLEVSKY, SolverOptions.PCG, |
if not method in [ SolverOptions.DEFAULT, SolverOptions.DIRECT, SolverOptions.CHOLEVSKY, SolverOptions.PCG, |
395 |
SolverOptions.CR, SolverOptions.CGS, SolverOptions.BICGSTAB, SolverOptions.SSOR, |
SolverOptions.CR, SolverOptions.CGS, SolverOptions.BICGSTAB, SolverOptions.SSOR, |
396 |
SolverOptions.GMRES, SolverOptions.PRES20, SolverOptions.LUMPING, SolverOptions.ITERATIVE, SolverOptions.AMG, |
SolverOptions.GMRES, SolverOptions.PRES20, SolverOptions.LUMPING, SolverOptions.ITERATIVE, SolverOptions.AMG, |
417 |
@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} |
@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} |
418 |
@note: Not all packages are support on all implementation. An exception may be thrown on some platforms if a particular is requested. |
@note: Not all packages are support on all implementation. An exception may be thrown on some platforms if a particular is requested. |
419 |
""" |
""" |
420 |
|
if package==None: package=0 |
421 |
if not package in [SolverOptions.DEFAULT, SolverOptions.PASO, SolverOptions.SUPER_LU, SolverOptions.PASTIX, SolverOptions.MKL, SolverOptions.UMFPACK, SolverOptions.TRILINOS]: |
if not package in [SolverOptions.DEFAULT, SolverOptions.PASO, SolverOptions.SUPER_LU, SolverOptions.PASTIX, SolverOptions.MKL, SolverOptions.UMFPACK, SolverOptions.TRILINOS]: |
422 |
raise ValueError,"unknown solver package %s"%package |
raise ValueError,"unknown solver package %s"%package |
423 |
self.__package=package |
self.__package=package |
463 |
if restart<1: |
if restart<1: |
464 |
raise ValueError,"restart must be positive." |
raise ValueError,"restart must be positive." |
465 |
self.__restart=restart |
self.__restart=restart |
466 |
|
|
467 |
def getRestart(self): |
def getRestart(self): |
468 |
""" |
""" |
469 |
Returns the number of iterations steps after which GMRES is performing a restart. |
Returns the number of iterations steps after which GMRES is performing a restart. |
475 |
return None |
return None |
476 |
else: |
else: |
477 |
return self.__restart |
return self.__restart |
478 |
|
def _getRestartForC(self): |
479 |
|
r=self.getRestart() |
480 |
|
if r == None: |
481 |
|
return -1 |
482 |
|
else: |
483 |
|
return r |
484 |
def setTruncation(self,truncation=20): |
def setTruncation(self,truncation=20): |
485 |
""" |
""" |
486 |
Sets the number of residuals in GMRES to be stored for orthogonalization. The more residuals are stored |
Sets the number of residuals in GMRES to be stored for orthogonalization. The more residuals are stored |
789 |
Switches the verbosity of the solver off. |
Switches the verbosity of the solver off. |
790 |
""" |
""" |
791 |
self.__verbose=False |
self.__verbose=False |
792 |
def setVerbosity(self,verbose=True): |
def setVerbosity(self,verbose=False): |
793 |
""" |
""" |
794 |
Sets the verbosity flag for the solver to C{flag}. |
Sets the verbosity flag for the solver to C{flag}. |
795 |
|
|
800 |
self.setVerbosityOn() |
self.setVerbosityOn() |
801 |
else: |
else: |
802 |
self.setVerbosityOff() |
self.setVerbosityOff() |
803 |
|
|
|
self.__adapt_inner_tolerance=True |
|
804 |
def adaptInnerTolerance(self): |
def adaptInnerTolerance(self): |
805 |
""" |
""" |
806 |
Returns C{True} if the tolerance of the inner solver is selected automatically. |
Returns C{True} if the tolerance of the inner solver is selected automatically. |
1221 |
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 |
1222 |
problem will be solved to get the unknown M{u}. |
problem will be solved to get the unknown M{u}. |
1223 |
|
|
1224 |
@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" |
|
|
|
|
|
|
|
1225 |
def __init__(self,domain,numEquations=None,numSolutions=None,debug=False): |
def __init__(self,domain,numEquations=None,numSolutions=None,debug=False): |
1226 |
""" |
""" |
1227 |
Initializes a linear problem. |
Initializes a linear problem. |
1245 |
self.__altered_coefficients=False |
self.__altered_coefficients=False |
1246 |
self.__reduce_equation_order=False |
self.__reduce_equation_order=False |
1247 |
self.__reduce_solution_order=False |
self.__reduce_solution_order=False |
1248 |
self.__tolerance=1.e-8 |
self.__sym=False |
1249 |
self.__solver_method=self.DEFAULT |
self.setSolverOptions() |
|
self.__solver_package=self.DEFAULT |
|
|
self.__preconditioner=self.DEFAULT |
|
1250 |
self.__is_RHS_valid=False |
self.__is_RHS_valid=False |
1251 |
self.__is_operator_valid=False |
self.__is_operator_valid=False |
|
self.__sym=False |
|
1252 |
self.__COEFFICIENTS={} |
self.__COEFFICIENTS={} |
1253 |
|
self.__solution_rtol=1.e99 |
1254 |
|
self.__solution_atol=1.e99 |
1255 |
|
self.setSymmetryOff() |
1256 |
# initialize things: |
# initialize things: |
1257 |
self.resetAllCoefficients() |
self.resetAllCoefficients() |
1258 |
self.__system_type=None |
self.initializeSystem() |
|
self.updateSystemType() |
|
1259 |
# ========================================================================== |
# ========================================================================== |
1260 |
# general stuff: |
# general stuff: |
1261 |
# ========================================================================== |
# ========================================================================== |
1420 |
# ========================================================================== |
# ========================================================================== |
1421 |
# solver settings: |
# solver settings: |
1422 |
# ========================================================================== |
# ========================================================================== |
1423 |
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} |
|
1424 |
""" |
""" |
1425 |
return self.__solver_package |
Sets the solver options. |
1426 |
|
|
1427 |
|
@param options: the new solver options. If equal C{None}, the solver options are set to the default. |
1428 |
|
@type options: L{SolverOptions} or C{None} |
1429 |
|
@note: The symmetry flag of options is overwritten by the symmetry flag of the L{LinearProblem}. |
1430 |
|
""" |
1431 |
|
if options==None: |
1432 |
|
self.__solver_options=SolverOptions() |
1433 |
|
elif isinstance(options, SolverOptions): |
1434 |
|
self.__solver_options=options |
1435 |
|
else: |
1436 |
|
raise ValueError,"options must be a SolverOptions object." |
1437 |
|
self.__solver_options.setSymmetry(self.__sym) |
1438 |
|
|
1439 |
|
def getSolverOptions(self): |
1440 |
|
""" |
1441 |
|
Returns the solver options |
1442 |
|
|
1443 |
|
@rtype: L{SolverOptions} |
1444 |
|
""" |
1445 |
|
self.__solver_options.setSymmetry(self.__sym) |
1446 |
|
return self.__solver_options |
1447 |
|
|
1448 |
def isUsingLumping(self): |
def isUsingLumping(self): |
1449 |
""" |
""" |
1450 |
Checks if matrix lumping is the current solver method. |
Checks if matrix lumping is the current solver method. |
1452 |
@return: True if the current solver method is lumping |
@return: True if the current solver method is lumping |
1453 |
@rtype: C{bool} |
@rtype: C{bool} |
1454 |
""" |
""" |
1455 |
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 |
|
|
|
|
1456 |
# ========================================================================== |
# ========================================================================== |
1457 |
# symmetry flag: |
# symmetry flag: |
1458 |
# ========================================================================== |
# ========================================================================== |
1462 |
|
|
1463 |
@return: True if a symmetric PDE is indicated, False otherwise |
@return: True if a symmetric PDE is indicated, False otherwise |
1464 |
@rtype: C{bool} |
@rtype: C{bool} |
1465 |
|
@note: the method is equivalent to use getSolverOptions().isSymmetric() |
1466 |
""" |
""" |
1467 |
return self.__sym |
self.getSolverOptions().isSymmetric() |
1468 |
|
|
1469 |
def setSymmetryOn(self): |
def setSymmetryOn(self): |
1470 |
""" |
""" |
1471 |
Sets the symmetry flag. |
Sets the symmetry flag. |
1472 |
|
@note: The method overwrites the symmetry flag set by the solver options |
1473 |
""" |
""" |
1474 |
if not self.isSymmetric(): |
self.__sym=True |
1475 |
self.trace("PDE is set to be symmetric") |
self.getSolverOptions().setSymmetryOn() |
|
self.__sym=True |
|
|
self.updateSystemType() |
|
1476 |
|
|
1477 |
def setSymmetryOff(self): |
def setSymmetryOff(self): |
1478 |
""" |
""" |
1479 |
Clears the symmetry flag. |
Clears the symmetry flag. |
1480 |
|
@note: The method overwrites the symmetry flag set by the solver options |
1481 |
""" |
""" |
1482 |
if self.isSymmetric(): |
self.__sym=False |
1483 |
self.trace("PDE is set to be nonsymmetric") |
self.getSolverOptions().setSymmetryOff() |
|
self.__sym=False |
|
|
self.updateSystemType() |
|
1484 |
|
|
1485 |
def setSymmetryTo(self,flag=False): |
def setSymmetry(self,flag=False): |
1486 |
""" |
""" |
1487 |
Sets the symmetry flag to C{flag}. |
Sets the symmetry flag to C{flag}. |
1488 |
|
|
1489 |
@param flag: If True, the symmetry flag is set otherwise reset. |
@param flag: If True, the symmetry flag is set otherwise reset. |
1490 |
@type flag: C{bool} |
@type flag: C{bool} |
1491 |
|
@note: The method overwrites the symmetry flag set by the solver options |
1492 |
""" |
""" |
1493 |
if flag: |
self.getSolverOptions().setSymmetry(flag) |
|
self.setSymmetryOn() |
|
|
else: |
|
|
self.setSymmetryOff() |
|
|
|
|
1494 |
# ========================================================================== |
# ========================================================================== |
1495 |
# function space handling for the equation as well as the solution |
# function space handling for the equation as well as the solution |
1496 |
# ========================================================================== |
# ========================================================================== |
1617 |
self.setReducedOrderForEquationOn() |
self.setReducedOrderForEquationOn() |
1618 |
else: |
else: |
1619 |
self.setReducedOrderForEquationOff() |
self.setReducedOrderForEquationOff() |
1620 |
|
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): |
|
1621 |
""" |
""" |
1622 |
Returns the current system type. |
Returns the current system type. |
1623 |
""" |
""" |
1624 |
return self.__system_type |
return self.__operator_type |
1625 |
|
|
1626 |
def checkSymmetricTensor(self,name,verbose=True): |
def checkSymmetricTensor(self,name,verbose=True): |
1627 |
""" |
""" |
1635 |
@return: True if coefficient C{name} is symmetric |
@return: True if coefficient C{name} is symmetric |
1636 |
@rtype: C{bool} |
@rtype: C{bool} |
1637 |
""" |
""" |
1638 |
|
SMALL_TOLERANCE=util.EPSILON*10. |
1639 |
A=self.getCoefficient(name) |
A=self.getCoefficient(name) |
1640 |
verbose=verbose or self.__debug |
verbose=verbose or self.__debug |
1641 |
out=True |
out=True |
1642 |
if not A.isEmpty(): |
if not A.isEmpty(): |
1643 |
tol=util.Lsup(A)*self.SMALL_TOLERANCE |
tol=util.Lsup(A)*SMALL_TOLERANCE |
1644 |
s=A.getShape() |
s=A.getShape() |
1645 |
if A.getRank() == 4: |
if A.getRank() == 4: |
1646 |
if s[0]==s[2] and s[1] == s[3]: |
if s[0]==s[2] and s[1] == s[3]: |
1685 |
symmetric. |
symmetric. |
1686 |
@rtype: C{bool} |
@rtype: C{bool} |
1687 |
""" |
""" |
1688 |
|
SMALL_TOLERANCE=util.EPSILON*10. |
1689 |
B=self.getCoefficient(name0) |
B=self.getCoefficient(name0) |
1690 |
C=self.getCoefficient(name1) |
C=self.getCoefficient(name1) |
1691 |
verbose=verbose or self.__debug |
verbose=verbose or self.__debug |
1699 |
elif not B.isEmpty() and not C.isEmpty(): |
elif not B.isEmpty() and not C.isEmpty(): |
1700 |
sB=B.getShape() |
sB=B.getShape() |
1701 |
sC=C.getShape() |
sC=C.getShape() |
1702 |
tol=(util.Lsup(B)+util.Lsup(C))*self.SMALL_TOLERANCE/2. |
tol=(util.Lsup(B)+util.Lsup(C))*SMALL_TOLERANCE/2. |
1703 |
if len(sB) != len(sC): |
if len(sB) != len(sC): |
1704 |
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)) |
1705 |
out=False |
out=False |
1844 |
""" |
""" |
1845 |
Returns True if the solution is still valid. |
Returns True if the solution is still valid. |
1846 |
""" |
""" |
1847 |
|
if self.__solution_rtol>self.getSolverOptions().getTolerance() or \ |
1848 |
|
self.__solution_atol>self.getSolverOptions().getAbsoluteTolerance(): |
1849 |
|
self.invalidateSolution() |
1850 |
return self.__is_solution_valid |
return self.__is_solution_valid |
1851 |
|
|
1852 |
def validOperator(self): |
def validOperator(self): |
1867 |
""" |
""" |
1868 |
Returns True if the operator is still valid. |
Returns True if the operator is still valid. |
1869 |
""" |
""" |
1870 |
|
if self.getRequiredOperatorType()==self.getOperatorType(): self.invalidateOperator() |
1871 |
return self.__is_operator_valid |
return self.__is_operator_valid |
1872 |
|
|
1873 |
def validRightHandSide(self): |
def validRightHandSide(self): |
1894 |
""" |
""" |
1895 |
Announces that everything has to be rebuilt. |
Announces that everything has to be rebuilt. |
1896 |
""" |
""" |
|
if self.isRightHandSideValid(): self.trace("System has to be rebuilt.") |
|
1897 |
self.invalidateSolution() |
self.invalidateSolution() |
1898 |
self.invalidateOperator() |
self.invalidateOperator() |
1899 |
self.invalidateRightHandSide() |
self.invalidateRightHandSide() |
1909 |
Resets the system clearing the operator, right hand side and solution. |
Resets the system clearing the operator, right hand side and solution. |
1910 |
""" |
""" |
1911 |
self.trace("New System has been created.") |
self.trace("New System has been created.") |
1912 |
|
self.__operator_type=None |
1913 |
self.__operator=escript.Operator() |
self.__operator=escript.Operator() |
1914 |
self.__righthandside=escript.Data() |
self.__righthandside=escript.Data() |
1915 |
self.__solution=escript.Data() |
self.__solution=escript.Data() |
1964 |
|
|
1965 |
def setSolution(self,u): |
def setSolution(self,u): |
1966 |
""" |
""" |
1967 |
Sets the solution assuming that makes the system valid. |
Sets the solution assuming that makes the system valid with the tolrance |
1968 |
|
defined by the solver options |
1969 |
""" |
""" |
1970 |
|
self.__solution_rtol=self.getSolverOptions().getTolerance() |
1971 |
|
self.__solution_atol=self.getSolverOptions().getAbsoluteTolerance() |
1972 |
self.__solution=u |
self.__solution=u |
1973 |
self.validSolution() |
self.validSolution() |
1974 |
|
|
2001 |
Makes sure that the operator is instantiated and returns it initialized |
Makes sure that the operator is instantiated and returns it initialized |
2002 |
with zeros. |
with zeros. |
2003 |
""" |
""" |
2004 |
if self.__operator.isEmpty(): |
if self.getOperatorType() == None: |
2005 |
if self.isUsingLumping(): |
if self.isUsingLumping(): |
2006 |
self.__operator=self.createSolution() |
self.__operator=self.createSolution() |
2007 |
else: |
else: |
2008 |
self.__operator=self.createOperator() |
self.__operator=self.createOperator() |
2009 |
|
self.__operator_type=self.getRequiredOperatorType() |
2010 |
else: |
else: |
2011 |
if self.isUsingLumping(): |
if self.isUsingLumping(): |
2012 |
self.__operator.setToZero() |
self.__operator.setToZero() |
2018 |
""" |
""" |
2019 |
Returns the operator in its current state. |
Returns the operator in its current state. |
2020 |
""" |
""" |
|
if self.__operator.isEmpty(): self.resetOperator() |
|
2021 |
return self.__operator |
return self.__operator |
2022 |
|
|
2023 |
def setValue(self,**coefficients): |
def setValue(self,**coefficients): |
2079 |
# methods that are typically overwritten when implementing a particular |
# methods that are typically overwritten when implementing a particular |
2080 |
# linear problem |
# linear problem |
2081 |
# ========================================================================== |
# ========================================================================== |
2082 |
def getRequiredSystemType(self): |
def getRequiredOperatorType(self): |
2083 |
""" |
""" |
2084 |
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. |
2085 |
|
|
2086 |
@note: Typically this method is overwritten when implementing a |
@note: Typically this method is overwritten when implementing a |
2087 |
particular linear problem. |
particular linear problem. |
2088 |
""" |
""" |
2089 |
return 0 |
return None |
2090 |
|
|
2091 |
def createOperator(self): |
def createOperator(self): |
2092 |
""" |
""" |
2135 |
linear problem. |
linear problem. |
2136 |
""" |
""" |
2137 |
return (self.getCurrentOperator(), self.getCurrentRightHandSide()) |
return (self.getCurrentOperator(), self.getCurrentRightHandSide()) |
|
#===================== |
|
2138 |
|
|
2139 |
class LinearPDE(LinearProblem): |
class LinearPDE(LinearProblem): |
2140 |
""" |
""" |
2319 |
""" |
""" |
2320 |
return "<LinearPDE %d>"%id(self) |
return "<LinearPDE %d>"%id(self) |
2321 |
|
|
2322 |
def getRequiredSystemType(self): |
def getRequiredOperatorType(self): |
2323 |
""" |
""" |
2324 |
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. |
2325 |
""" |
""" |
2326 |
return self.getDomain().getSystemMatrixTypeId(self.getSolverMethod()[0],self.getSolverMethod()[1],self.getSolverPackage(),self.isSymmetric()) |
solver_options=self.getSolverOptions() |
2327 |
|
return self.getDomain().getSystemMatrixTypeId(solver_options.getSolverMethod(), solver_options.getPreconditioner(),solver_options.getPackage(), solver_options.isSymmetric()) |
2328 |
|
|
2329 |
def checkSymmetry(self,verbose=True): |
def checkSymmetry(self,verbose=True): |
2330 |
""" |
""" |
2355 |
""" |
""" |
2356 |
Returns an instance of a new operator. |
Returns an instance of a new operator. |
2357 |
""" |
""" |
2358 |
self.trace("New operator is allocated.") |
optype=self.getRequiredOperatorType() |
2359 |
|
self.trace("New operator of type %s is allocated."%optype) |
2360 |
return self.getDomain().newOperator( \ |
return self.getDomain().newOperator( \ |
2361 |
self.getNumEquations(), \ |
self.getNumEquations(), \ |
2362 |
self.getFunctionSpaceForEquation(), \ |
self.getFunctionSpaceForEquation(), \ |
2363 |
self.getNumSolutions(), \ |
self.getNumSolutions(), \ |
2364 |
self.getFunctionSpaceForSolution(), \ |
self.getFunctionSpaceForSolution(), \ |
2365 |
self.getSystemType()) |
optype) |
2366 |
|
|
2367 |
def getSolution(self,**options): |
def getSolution(self): |
2368 |
""" |
""" |
2369 |
Returns the solution of the PDE. |
Returns the solution of the PDE. |
2370 |
|
|
2371 |
@return: the solution |
@return: the solution |
2372 |
@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} |
|
2373 |
""" |
""" |
2374 |
|
option_class=self.getSolverOptions() |
2375 |
if not self.isSolutionValid(): |
if not self.isSolutionValid(): |
2376 |
mat,f=self.getSystem() |
mat,f=self.getSystem() |
2377 |
if self.isUsingLumping(): |
if self.isUsingLumping(): |
2378 |
self.setSolution(f*1/mat) |
self.setSolution(f*1/mat) |
2379 |
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() |
|
2380 |
self.trace("PDE is resolved.") |
self.trace("PDE is resolved.") |
2381 |
self.trace("solver options: %s"%str(options)) |
self.trace("solver options: %s"%str(option_class)) |
2382 |
self.setSolution(mat.solve(f,options)) |
self.setSolution(mat.solve(f,option_class)) |
2383 |
return self.getCurrentSolution() |
return self.getCurrentSolution() |
2384 |
|
|
2385 |
def getSystem(self): |
def getSystem(self): |
3352 |
theta=1. |
theta=1. |
3353 |
else: |
else: |
3354 |
theta=0.5 |
theta=0.5 |
3355 |
|
optype=self.getRequiredOperatorType() |
3356 |
self.trace("New Transport problem is allocated.") |
self.trace("New Transport problem pf type %s is allocated."%optype) |
3357 |
return self.getDomain().newTransportProblem( \ |
return self.getDomain().newTransportProblem( \ |
3358 |
theta, |
theta, |
3359 |
self.getNumEquations(), \ |
self.getNumEquations(), \ |
3360 |
self.getFunctionSpaceForSolution(), \ |
self.getFunctionSpaceForSolution(), \ |
3361 |
self.getSystemType()) |
optype) |
3362 |
|
|
3363 |
def setInitialSolution(self,u): |
def setInitialSolution(self,u): |
3364 |
""" |
""" |
3378 |
raise ValueError,"Illegal shape %s of initial solution."%(u2.getShape(),) |
raise ValueError,"Illegal shape %s of initial solution."%(u2.getShape(),) |
3379 |
self.getOperator().setInitialValue(u2) |
self.getOperator().setInitialValue(u2) |
3380 |
|
|
3381 |
def getRequiredSystemType(self): |
def getRequiredOperatorType(self): |
3382 |
""" |
""" |
3383 |
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. |
3384 |
|
|
3385 |
@return: a code to indicate the type of transport problem scheme used |
@return: a code to indicate the type of transport problem scheme used |
3386 |
@rtype: C{float} |
@rtype: C{float} |
3387 |
""" |
""" |
3388 |
return self.getDomain().getTransportTypeId(self.getSolverMethod()[0],self.getSolverMethod()[1],self.getSolverPackage(),self.isSymmetric()) |
solver_options=self.getSolverOptions() |
3389 |
|
return self.getDomain().getTransportTypeId(solver_options.getSolverMethod(), solver_options.getPreconditioner(),solver_options.getPackage(), solver_options.isSymmetric()) |
3390 |
|
|
3391 |
def getUnlimitedTimeStepSize(self): |
def getUnlimitedTimeStepSize(self): |
3392 |
""" |
""" |
3431 |
""" |
""" |
3432 |
return self.__constraint_factor |
return self.__constraint_factor |
3433 |
#==================================================================== |
#==================================================================== |
3434 |
def getSolution(self,dt,**options): |
def getSolution(self,dt): |
3435 |
""" |
""" |
3436 |
Returns the solution of the problem. |
Returns the solution of the problem. |
3437 |
|
|
3438 |
@return: the solution |
@return: the solution |
3439 |
@rtype: L{Data<escript.Data>} |
@rtype: L{Data<escript.Data>} |
|
|
|
3440 |
""" |
""" |
3441 |
|
option_class=self.getSolverOptions() |
3442 |
if dt<=0: |
if dt<=0: |
3443 |
raise ValueError,"step size needs to be positive." |
raise ValueError,"step size needs to be positive." |
3444 |
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)) |
|
3445 |
self.validSolution() |
self.validSolution() |
3446 |
return self.getCurrentSolution() |
return self.getCurrentSolution() |
3447 |
|
|