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

Contents of /trunk/esys2/escript/py_src/linearPDEs.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 104 - (show annotations)
Fri Dec 17 07:43:12 2004 UTC (18 years, 3 months ago) by jgs
File MIME type: text/x-python
File size: 36737 byte(s)
*** empty log message ***

1 # $Id$
2
3 ## @file linearPDEs.py
4
5 """
6 @brief Functions and classes for linear PDEs
7 """
8
9 import escript
10 import util
11 import numarray
12
13 def identifyDomain(domain=None,data={}):
14 """
15 @brief Return the Domain which is equal to the input domain (if not None)
16 and is the domain of all Data objects in the dictionary data.
17 An exception is raised if this is not possible
18
19 @param domain
20 @param data
21 """
22 # get the domain used by any Data object in the list data:
23 data_domain=None
24 for d in data.itervalues():
25 if isinstance(d,escript.Data):
26 if not d.isEmpty(): data_domain=d.getDomain()
27 # check if domain and data_domain are identical?
28 if domain == None:
29 if data_domain == None:
30 raise ValueError,"Undefined PDE domain. Specify a domain or use a Data class object as coefficient"
31 else:
32 if data_domain == None:
33 data_domain=domain
34 else:
35 if not data_domain == domain:
36 raise ValueError,"Domain of coefficients doesnot match specified domain"
37 # now we check if all Data class object coefficients are defined on data_domain:
38 for i,d in data.iteritems():
39 if isinstance(d,escript.Data):
40 if not d.isEmpty():
41 if not data_domain==d.getDomain():
42 raise ValueError,"Illegal domain for coefficient %s."%i
43 # done:
44 return data_domain
45
46 def identifyNumEquationsAndSolutions(dim,coef={}):
47 # get number of equations and number of unknowns:
48 numEquations=0
49 numSolutions=0
50 for i in coef.iterkeys():
51 if not coef[i].isEmpty():
52 res=_PDECoefficientTypes[i].estimateNumEquationsAndNumSolutions(coef[i].getShape(),dim)
53 if res==None:
54 raise ValueError,"Illegal shape %s of coefficient %s"%(coef[i].getShape().__str__(),i)
55 else:
56 numEquations=max(numEquations,res[0])
57 numSolutions=max(numSolutions,res[1])
58 return numEquations,numSolutions
59
60
61 def _CompTuple2(t1,t2):
62 """
63 @brief
64
65 @param t1
66 @param t2
67 """
68 dif=t1[0]+t1[1]-(t2[0]+t2[1])
69 if dif<0: return 1
70 elif dif>0: return -1
71 else: return 0
72
73 class PDECoefficientType:
74 """
75 @brief
76 """
77 # identifier for location of Data objects defining coefficients
78 INTERIOR=0
79 BOUNDARY=1
80 CONTACT=2
81 CONTINUOUS=3
82 # identifier in the pattern of coefficients:
83 # the pattern is a tuple of EQUATION,SOLUTION,DIM where DIM represents the spatial dimension, EQUATION the number of equations and SOLUTION the
84 # number of unknowns.
85 EQUATION=3
86 SOLUTION=4
87 DIM=5
88 # indicator for what is altered if the coefficient is altered:
89 OPERATOR=5
90 RIGHTHANDSIDE=6
91 BOTH=7
92 def __init__(self,where,pattern,altering):
93 """
94 @brief Initialise a PDE Coefficient type
95 """
96 self.what=where
97 self.pattern=pattern
98 self.altering=altering
99
100 def getFunctionSpace(self,domain):
101 """
102 @brief defines the FunctionSpace of the coefficient on the domain
103
104 @param domain
105 """
106 if self.what==self.INTERIOR: return escript.Function(domain)
107 elif self.what==self.BOUNDARY: return escript.FunctionOnBoundary(domain)
108 elif self.what==self.CONTACT: return escript.FunctionOnContactZero(domain)
109 elif self.what==self.CONTINUOUS: return escript.ContinuousFunction(domain)
110
111 def isAlteringOperator(self):
112 """
113 @brief return true if the operator of the PDE is changed when the coefficient is changed
114 """
115 if self.altering==self.OPERATOR or self.altering==self.BOTH:
116 return not None
117 else:
118 return None
119
120 def isAlteringRightHandSide(self):
121 """
122 @brief return true if the right hand side of the PDE is changed when the coefficient is changed
123 """
124 if self.altering==self.RIGHTHANDSIDE or self.altering==self.BOTH:
125 return not None
126 else:
127 return None
128
129 def estimateNumEquationsAndNumSolutions(self,shape=(),dim=3):
130 """
131 @brief tries to estimate the number of equations in a given tensor shape for a given spatial dimension dim
132
133 @param shape
134 @param dim
135 """
136 if len(shape)>0:
137 num=max(shape)+1
138 else:
139 num=1
140 search=[]
141 for u in range(num):
142 for e in range(num):
143 search.append((e,u))
144 search.sort(_CompTuple2)
145 for item in search:
146 s=self.buildShape(item[0],item[1],dim)
147 if len(s)==0 and len(shape)==0:
148 return (1,1)
149 else:
150 if s==shape: return item
151 return None
152
153 def buildShape(self,e=1,u=1,dim=3):
154 """
155 @brief builds the required shape for a given number of equations e, number of unknowns u and spatial dimension dim
156
157 @param e
158 @param u
159 @param dim
160 """
161 s=()
162 for i in self.pattern:
163 if i==self.EQUATION:
164 if e>1: s=s+(e,)
165 elif i==self.SOLUTION:
166 if u>1: s=s+(u,)
167 else:
168 s=s+(dim,)
169 return s
170
171 _PDECoefficientTypes={
172 "A" : PDECoefficientType(PDECoefficientType.INTERIOR,(PDECoefficientType.EQUATION,PDECoefficientType.DIM,PDECoefficientType.SOLUTION,PDECoefficientType.DIM),PDECoefficientType.OPERATOR),
173 "B" : PDECoefficientType(PDECoefficientType.INTERIOR,(PDECoefficientType.EQUATION,PDECoefficientType.DIM,PDECoefficientType.SOLUTION),PDECoefficientType.OPERATOR),
174 "C" : PDECoefficientType(PDECoefficientType.INTERIOR,(PDECoefficientType.EQUATION,PDECoefficientType.SOLUTION,PDECoefficientType.DIM),PDECoefficientType.OPERATOR),
175 "D" : PDECoefficientType(PDECoefficientType.INTERIOR,(PDECoefficientType.EQUATION,PDECoefficientType.SOLUTION),PDECoefficientType.OPERATOR),
176 "X" : PDECoefficientType(PDECoefficientType.INTERIOR,(PDECoefficientType.EQUATION,PDECoefficientType.DIM),PDECoefficientType.RIGHTHANDSIDE),
177 "Y" : PDECoefficientType(PDECoefficientType.INTERIOR,(PDECoefficientType.EQUATION,),PDECoefficientType.RIGHTHANDSIDE),
178 "d" : PDECoefficientType(PDECoefficientType.BOUNDARY,(PDECoefficientType.EQUATION,PDECoefficientType.SOLUTION),PDECoefficientType.OPERATOR),
179 "y" : PDECoefficientType(PDECoefficientType.BOUNDARY,(PDECoefficientType.EQUATION,),PDECoefficientType.RIGHTHANDSIDE),
180 "d_contact" : PDECoefficientType(PDECoefficientType.CONTACT,(PDECoefficientType.EQUATION,PDECoefficientType.SOLUTION),PDECoefficientType.OPERATOR),
181 "y_contact" : PDECoefficientType(PDECoefficientType.CONTACT,(PDECoefficientType.EQUATION,),PDECoefficientType.RIGHTHANDSIDE),
182 "r" : PDECoefficientType(PDECoefficientType.CONTINUOUS,(PDECoefficientType.EQUATION,),PDECoefficientType.RIGHTHANDSIDE),
183 "q" : PDECoefficientType(PDECoefficientType.CONTINUOUS,(PDECoefficientType.SOLUTION,),PDECoefficientType.BOTH),
184 }
185
186 class LinearPDE:
187 """
188 @brief Class to define a linear PDE
189
190 class to define a linear PDE of the form
191
192 -(A_{ijkl}u_{k,l})_{,j} -(B_{ijk}u_k)_{,j} + C_{ikl}u_{k,l} +D_{ik}u_k = - (X_{ij})_{,j} + Y_i
193
194 with boundary conditons:
195
196 n_j*(A_{ijkl}u_{k,l}+B_{ijk}u_k)_{,j} + d_{ik}u_k = - n_j*X_{ij} + y_i
197
198 and contact conditions
199
200 n_j*(A_{ijkl}u_{k,l}+B_{ijk}u_k)_{,j} + d_contact_{ik}[u_k] = - n_j*X_{ij} + y_contact_i
201
202 and constraints:
203
204 u_i=r_i where q_i>0
205
206 """
207 DEFAULT_METHOD=util.DEFAULT_METHOD
208 DIRECT=util.DIRECT
209 CHOLEVSKY=util.CHOLEVSKY
210 PCG=util.PCG
211 CR=util.CR
212 CGS=util.CGS
213 BICGSTAB=util.BICGSTAB
214 SSOR=util.SSOR
215 GMRES=util.GMRES
216 PRES20=util.PRES20
217
218 def __init__(self,domain,numEquations=0,numSolutions=0):
219 """
220 @brief initializes a new linear PDE.
221
222 @param args
223 """
224
225 # initialize attributes
226 self.__debug=None
227 self.__domain=domain
228 self.__numEquations=numEquations
229 self.__numSolutions=numSolutions
230 self.cleanCoefficients()
231
232 self.__operator=escript.Operator()
233 self.__operator_isValid=False
234 self.__righthandside=escript.Data()
235 self.__righthandside_isValid=False
236 self.__solution=escript.Data()
237 self.__solution_isValid=False
238
239 # set some default values:
240 self.__homogeneous_constraint=True
241 self.__row_function_space=escript.Solution(self.__domain)
242 self.__column_function_space=escript.Solution(self.__domain)
243 self.__tolerance=1.e-8
244 self.__solver_method=util.DEFAULT_METHOD
245 self.__matrix_type=self.__domain.getSystemMatrixTypeId(util.DEFAULT_METHOD,False)
246 self.__sym=False
247 self.__lumping=False
248
249 def getCoefficient(self,name):
250 """
251 @brief return the value of the coefficient name
252
253 @param name
254 """
255 return self.__coefficient[name]
256
257 def setValue(self,**coefficients):
258 """
259 @brief sets new values to coefficients
260
261 @param coefficients
262 """
263 self._setValue(**coefficients)
264
265
266 def _setValue(self,**coefficients):
267 """
268 @brief sets new values to coefficients
269
270 @param coefficients
271 """
272
273 # get the dictionary of the coefficinets been altered:
274 alteredCoefficients={}
275 for i,d in coefficients.iteritems():
276 if self.hasCoefficient(i):
277 if d == None:
278 alteredCoefficients[i]=escript.Data()
279 elif isinstance(d,escript.Data):
280 if d.isEmpty():
281 alteredCoefficients[i]=escript.Data()
282 else:
283 alteredCoefficients[i]=escript.Data(d,self.getFunctionSpaceOfCoefficient(i))
284 else:
285 alteredCoefficients[i]=escript.Data(d,self.getFunctionSpaceOfCoefficient(i))
286 else:
287 raise ValueError,"Attempt to set undefined coefficient %s"%i
288 # if numEquations and numSolutions is undefined we try identify their values based on the coefficients:
289 if self.__numEquations<1 or self.__numSolutions<1:
290 numEquations,numSolutions=identifyNumEquationsAndSolutions(self.getDomain().getDim(),alteredCoefficients)
291 if self.__numEquations<1 and numEquations>0: self.__numEquations=numEquations
292 if self.__numSolutions<1 and numSolutions>0: self.__numSolutions=numSolutions
293 if self.debug() and self.__numEquations>0: print "PDE Debug: identified number of equations is ",self.__numEquations
294 if self.debug() and self.__numSolutions>0: print "PDE Debug: identified number of solutions is ",self.__numSolutions
295
296 # now we check the shape of the coefficient if numEquations and numSolutions are set:
297 if self.__numEquations>0 and self.__numSolutions>0:
298 for i in self.__coefficient.iterkeys():
299 if alteredCoefficients.has_key(i) and not alteredCoefficients[i].isEmpty():
300 if not self.getShapeOfCoefficient(i)==alteredCoefficients[i].getShape():
301 raise ValueError,"Expected shape for coefficient %s is %s but actual shape is %s."%(i,self.getShapeOfCoefficient(i),alteredCoefficients[i].getShape())
302 else:
303 if not self.__coefficient[i].isEmpty():
304 if not self.getShapeOfCoefficient(i)==self.__coefficient[i].getShape():
305 raise ValueError,"Expected shape for coefficient %s is %s but actual shape is %s."%(i,self.getShapeOfCoefficient(i),self.__coefficient[i].getShape())
306 # overwrite new values:
307 for i,d in alteredCoefficients.iteritems():
308 if self.debug(): print "PDE Debug: Coefficient %s has been altered."%i
309 self.__coefficient[i]=d
310 self.alteredCoefficient(i)
311
312 # reset the HomogeneousConstraintFlag:
313 self.__setHomogeneousConstraintFlag()
314 if not "q" in alteredCoefficients and not self.__homogeneous_constraint: self.__rebuildSystem()
315
316 def cleanCoefficients(self):
317 """
318 @brief resets all coefficients to default values.
319 """
320 self.__coefficient={}
321 for i in _PDECoefficientTypes.iterkeys():
322 self.__coefficient[i]=escript.Data()
323
324 def getShapeOfCoefficient(self,name):
325 """
326 @brief return the shape of the coefficient name
327
328 @param name
329 """
330 if self.hasCoefficient(name):
331 return _PDECoefficientTypes[name].buildShape(self.getNumEquations(),self.getNumSolutions(),self.getDomain().getDim())
332 else:
333 raise ValueError,"Solution coefficient %s requested"%name
334
335 def getFunctionSpaceOfCoefficient(self,name):
336 """
337 @brief return the atoms of the coefficient name
338
339 @param name
340 """
341 if self.hasCoefficient(name):
342 return _PDECoefficientTypes[name].getFunctionSpace(self.getDomain())
343 else:
344 raise ValueError,"Solution coefficient %s requested"%name
345
346 def alteredCoefficient(self,name):
347 """
348 @brief annonced that coefficient name has been changed
349
350 @param name
351 """
352 if self.hasCoefficient(name):
353 if _PDECoefficientTypes[name].isAlteringOperator(): self.__rebuildOperator()
354 if _PDECoefficientTypes[name].isAlteringRightHandSide(): self.__rebuildRightHandSide()
355 else:
356 raise ValueError,"Solution coefficient %s requested"%name
357
358 def __setHomogeneousConstraintFlag(self):
359 """
360 @brief checks if the constraints are homogeneous and sets self.__homogeneous_constraint accordingly.
361 """
362 self.__homogeneous_constraint=True
363 q=self.getCoefficient("q")
364 r=self.getCoefficient("r")
365 if not q.isEmpty() and not r.isEmpty():
366 print (q*r).Lsup(), 1.e-13*r.Lsup()
367 if (q*r).Lsup()>=1.e-13*r.Lsup(): self.__homogeneous_constraint=False
368 if self.debug():
369 if self.__homogeneous_constraint:
370 print "PDE Debug: Constraints are homogeneous."
371 else:
372 print "PDE Debug: Constraints are inhomogeneous."
373
374
375 def hasCoefficient(self,name):
376 """
377 @brief return true if name is the name of a coefficient
378
379 @param name
380 """
381 return self.__coefficient.has_key(name)
382
383 def getFunctionSpaceForEquation(self):
384 """
385 @brief return true if the test functions should use reduced order
386 """
387 return self.__row_function_space
388
389 def getFunctionSpaceForSolution(self):
390 """
391 @brief return true if the interpolation of the solution should use reduced order
392 """
393 return self.__column_function_space
394
395 # ===== debug ==============================================================
396 def setDebugOn(self):
397 """
398 @brief
399 """
400 self.__debug=not None
401
402 def setDebugOff(self):
403 """
404 @brief
405 """
406 self.__debug=None
407
408 def debug(self):
409 """
410 @brief returns true if the PDE is in the debug mode
411 """
412 return self.__debug
413
414 #===== Lumping ===========================
415 def setLumpingOn(self):
416 """
417 @brief indicates to use matrix lumping
418 """
419 if not self.isUsingLumping():
420 raise SystemError,"Lumping is not working yet! Talk to the experts"
421 if self.debug() : print "PDE Debug: lumping is set on"
422 self.__rebuildOperator()
423 self.__lumping=True
424
425 def setLumpingOff(self):
426 """
427 @brief switches off matrix lumping
428 """
429 if self.isUsingLumping():
430 if self.debug() : print "PDE Debug: lumping is set off"
431 self.__rebuildOperator()
432 self.__lumping=False
433
434 def setLumping(self,flag=False):
435 """
436 @brief set the matrix lumping flag to flag
437 """
438 if flag:
439 self.setLumpingOn()
440 else:
441 self.setLumpingOff()
442
443 def isUsingLumping(self):
444 """
445 @brief
446 """
447 return self.__lumping
448
449 #============ method business =========================================================
450 def setSolverMethod(self,solver=util.DEFAULT_METHOD):
451 """
452 @brief sets a new solver
453 """
454 if not solver==self.getSolverMethod():
455 self.__solver_method=solver
456 if self.debug() : print "PDE Debug: New solver is %s"%solver
457 self.__checkMatrixType()
458
459 def getSolverMethod(self):
460 """
461 @brief returns the solver method
462 """
463 return self.__solver_method
464
465 #============ tolerance business =========================================================
466 def setTolerance(self,tol=1.e-8):
467 """
468 @brief resets the tolerance to tol.
469 """
470 if not tol>0:
471 raise ValueException,"Tolerance as to be positive"
472 if tol<self.getTolerance(): self.__rebuildSolution()
473 if self.debug() : print "PDE Debug: New tolerance %e",tol
474 self.__tolerance=tol
475 return
476 def getTolerance(self):
477 """
478 @brief returns the tolerance set for the solution
479 """
480 return self.__tolerance
481
482 #===== symmetry flag ==========================
483 def isSymmetric(self):
484 """
485 @brief returns true is the operator is considered to be symmetric
486 """
487 return self.__sym
488
489 def setSymmetryOn(self):
490 """
491 @brief sets the symmetry flag to true
492 """
493 if not self.isSymmetric():
494 if self.debug() : print "PDE Debug: Operator is set to be symmetric"
495 self.__sym=True
496 self.__checkMatrixType()
497
498 def setSymmetryOff(self):
499 """
500 @brief sets the symmetry flag to false
501 """
502 if self.isSymmetric():
503 if self.debug() : print "PDE Debug: Operator is set to be unsymmetric"
504 self.__sym=False
505 self.__checkMatrixType()
506
507 def setSymmetryTo(self,flag=False):
508 """
509 @brief sets the symmetry flag to flag
510
511 @param flag
512 """
513 if flag:
514 self.setSymmetryOn()
515 else:
516 self.setSymmetryOff()
517
518 #===== order reduction ==========================
519 def setReducedOrderOn(self):
520 """
521 @brief switches to on reduced order
522 """
523 self.setReducedOrderForSolutionOn()
524 self.setReducedOrderForEquationOn()
525
526 def setReducedOrderOff(self):
527 """
528 @brief switches to full order
529 """
530 self.setReducedOrderForSolutionOff()
531 self.setReducedOrderForEquationOff()
532
533 def setReducedOrderTo(self,flag=False):
534 """
535 @brief sets order according to flag
536
537 @param flag
538 """
539 self.setReducedOrderForSolutionTo(flag)
540 self.setReducedOrderForEquationTo(flag)
541
542
543 #===== order reduction solution ==========================
544 def setReducedOrderForSolutionOn(self):
545 """
546 @brief switches to reduced order to interpolate solution
547 """
548 new_fs=escript.ReducedSolution(self.getDomain())
549 if self.getFunctionSpaceForSolution()!=new_fs:
550 if self.debug() : print "PDE Debug: Reduced order is used to interpolate solution."
551 self.__column_function_space=new_fs
552 self.__rebuildSystem(deep=True)
553
554 def setReducedOrderForSolutionOff(self):
555 """
556 @brief switches to full order to interpolate solution
557 """
558 new_fs=escript.Solution(self.getDomain())
559 if self.getFunctionSpaceForSolution()!=new_fs:
560 if self.debug() : print "PDE Debug: Full order is used to interpolate solution."
561 self.__column_function_space=new_fs
562 self.__rebuildSystem(deep=True)
563
564 def setReducedOrderForSolutionTo(self,flag=False):
565 """
566 @brief sets order for test functions according to flag
567
568 @param flag
569 """
570 if flag:
571 self.setReducedOrderForSolutionOn()
572 else:
573 self.setReducedOrderForSolutionOff()
574
575 #===== order reduction equation ==========================
576 def setReducedOrderForEquationOn(self):
577 """
578 @brief switches to reduced order for test functions
579 """
580 new_fs=escript.ReducedSolution(self.getDomain())
581 if self.getFunctionSpaceForEquation()!=new_fs:
582 if self.debug() : print "PDE Debug: Reduced order is used for test functions."
583 self.__row_function_space=new_fs
584 self.__rebuildSystem(deep=True)
585
586 def setReducedOrderForEquationOff(self):
587 """
588 @brief switches to full order for test functions
589 """
590 new_fs=escript.Solution(self.getDomain())
591 if self.getFunctionSpaceForEquation()!=new_fs:
592 if self.debug() : print "PDE Debug: Full order is used for test functions."
593 self.__row_function_space=new_fs
594 self.__rebuildSystem(deep=True)
595
596 def setReducedOrderForEquationTo(self,flag=False):
597 """
598 @brief sets order for test functions according to flag
599
600 @param flag
601 """
602 if flag:
603 self.setReducedOrderForEquationOn()
604 else:
605 self.setReducedOrderForEquationOff()
606
607
608 # ==== initialization =====================================================================
609 def __makeNewOperator(self):
610 """
611 @brief
612 """
613 return self.getDomain().newOperator( \
614 self.getNumEquations(), \
615 self.getFunctionSpaceForEquation(), \
616 self.getNumSolutions(), \
617 self.getFunctionSpaceForSolution(), \
618 self.__matrix_type)
619
620 def __makeNewRightHandSide(self):
621 """
622 @brief
623 """
624 return escript.Data(0.,(self.getNumEquations(),),self.getFunctionSpaceForEquation(),True)
625
626 def __makeNewSolution(self):
627 """
628 @brief
629 """
630 return escript.Data(0.,(self.getNumSolutions(),),self.getFunctionSpaceForSolution(),True)
631
632 def __getFreshOperator(self):
633 """
634 @brief
635 """
636 if self.__operator.isEmpty():
637 self.__operator=self.__makeNewOperator()
638 if self.debug() : print "PDE Debug: New operator allocated"
639 else:
640 self.__operator.setValue(0.)
641 if self.debug() : print "PDE Debug: Operator reset to zero"
642 return self.__operator
643
644 def __getFreshRightHandSide(self):
645 """
646 @brief
647 """
648 if self.__righthandside.isEmpty():
649 self.__righthandside=self.__makeNewRightHandSide()
650 if self.debug() : print "PDE Debug: New right hand side allocated"
651 else:
652 print "fix self.__righthandside*=0"
653 self.__righthandside*=0.
654 if self.debug() : print "PDE Debug: Right hand side reset to zero"
655 return self.__righthandside
656
657 # ==== rebuild switches =====================================================================
658 def __rebuildSolution(self,deep=False):
659 """
660 @brief indicates the PDE has to be reolved if the solution is requested
661 """
662 if self.__solution_isValid and self.debug() : print "PDE Debug: PDE has to be resolved."
663 self.__solution_isValid=False
664 if deep: self.__solution=escript.Data(deep)
665
666
667 def __rebuildOperator(self,deep=False):
668 """
669 @brief indicates the operator has to be rebuilt next time it is used
670 """
671 if self.__operator_isValid and self.debug() : print "PDE Debug: Operator has to be rebuilt."
672 self.__rebuildSolution(deep)
673 self.__operator_isValid=False
674 if deep: self.__operator=escript.Operator()
675
676 def __rebuildRightHandSide(self,deep=False):
677 """
678 @brief indicates the right hand side has to be rebuild next time it is used
679 """
680 if self.__righthandside_isValid and self.debug() : print "PDE Debug: Right hand side has to be rebuilt."
681 self.__rebuildSolution(deep)
682 self.__righthandside_isValid=False
683 if not self.__homogeneous_constraint: self.__rebuildOperator()
684 if deep: self.__righthandside=escript.Data()
685
686 def __rebuildSystem(self,deep=False):
687 """
688 @brief annonced that all coefficient name has been changed
689 """
690 self.__rebuildSolution(deep)
691 self.__rebuildOperator(deep)
692 self.__rebuildRightHandSide(deep)
693
694 def __checkMatrixType(self):
695 """
696 @brief reassess the matrix type and, if needed, initiates an operator rebuild
697 """
698 new_matrix_type=self.getDomain().getSystemMatrixTypeId(self.getSolverMethod(),self.isSymmetric())
699 if not new_matrix_type==self.__matrix_type:
700 if self.debug() : print "PDE Debug: Matrix type is now %d."%new_matrix_type
701 self.__matrix_type=new_matrix_type
702 self.__rebuildOperator(deep=True)
703
704 #============ assembling =======================================================
705 def __copyConstraint(self,u):
706 """
707 @brief copies the constrint condition into u
708 """
709 q=self.getCoefficient("q")
710 r=self.getCoefficient("r")
711 if not q.isEmpty():
712 if r.isEmpty():
713 r2=escript.Data(0,u.getShape(),u.getFunctionSpace())
714 else:
715 r2=escript.Data(r,u.getFunctionSpace())
716 u.copyWithMask(r2,escript.Data(q,u.getFunctionSpace()))
717
718 def __applyConstraint(self,rhs_update=True):
719 """
720 @brief applies the constraints defined by q and r to the system
721 """
722 q=self.getCoefficient("q")
723 r=self.getCoefficient("r")
724 if not q.isEmpty() and not self.__operator.isEmpty():
725 # q is the row and column mask to indicate where constraints are set:
726 row_q=escript.Data(q,self.getFunctionSpaceForEquation())
727 col_q=escript.Data(q,self.getFunctionSpaceForSolution())
728 u=self.__makeNewSolution()
729 if r.isEmpty():
730 r_s=self.__makeNewSolution()
731 else:
732 r_s=escript.Data(r,self.getFunctionSpaceForSolution())
733 u.copyWithMask(r_s,col_q)
734 if not self.__righthandside.isEmpty() and rhs_update: self.__righthandside-=self.__operator*u
735 self.__operator.nullifyRowsAndCols(row_q,col_q,1.)
736
737 def getOperator(self):
738 """
739 @brief returns the operator of the PDE
740 """
741 if not self.__operator_isValid:
742 # some Constraints are applying for a lumpled stifness matrix:
743 if self.isUsingLumping():
744 if self.getFunctionSpaceForEquation()==self.getFunctionSpaceForSolution():
745 raise TypeError,"Lumped matrix requires same order for equations and unknowns"
746 if not self.getCoefficient("A").isEmpty():
747 raise Warning,"Lumped matrix does not allow coefficient A"
748 if not self.getCoefficient("B").isEmpty():
749 raise Warning,"Lumped matrix does not allow coefficient B"
750 if not self.getCoefficient("C").isEmpty():
751 raise Warning,"Lumped matrix does not allow coefficient C"
752 if not self.getCoefficient("D").isEmpty():
753 raise Warning,"Lumped matrix does not allow coefficient D"
754 if self.debug() : print "PDE Debug: New lumped operator is built."
755 mat=self.__makeNewOperator(self)
756 else:
757 if self.debug() : print "PDE Debug: New operator is built."
758 mat=self.__getFreshOperator()
759
760 self.getDomain().addPDEToSystem(mat,escript.Data(), \
761 self.getCoefficient("A"), \
762 self.getCoefficient("B"), \
763 self.getCoefficient("C"), \
764 self.getCoefficient("D"), \
765 escript.Data(), \
766 escript.Data(), \
767 self.getCoefficient("d"), \
768 escript.Data(),\
769 self.getCoefficient("d_contact"), \
770 escript.Data())
771 if self.isUsingLumping():
772 self.__operator=mat*escript.Data(1,(self.getNumSolutions(),),self.getFunctionSpaceOfSolution(),True)
773 else:
774 self.__applyConstraint(rhs_update=False)
775 self.__operator_isValid=True
776 return self.__operator
777
778 def getRightHandSide(self,ignoreConstraint=False):
779 """
780 @brief returns the right hand side of the PDE
781
782 @param ignoreConstraint
783 """
784 if not self.__righthandside_isValid:
785 if self.debug() : print "PDE Debug: New right hand side is built."
786 self.getDomain().addPDEToRHS(self.__getFreshRightHandSide(), \
787 self.getCoefficient("X"), \
788 self.getCoefficient("Y"),\
789 self.getCoefficient("y"),\
790 self.getCoefficient("y_contact"))
791 self.__righthandside_isValid=True
792 if ignoreConstraint: self.__copyConstraint(self.__righthandside)
793 return self.__righthandside
794
795 def getSystem(self):
796 """
797 @brief
798 """
799 if not self.__operator_isValid and not self.__righthandside_isValid:
800 if self.debug() : print "PDE Debug: New PDE is built."
801 if self.isUsingLumping():
802 self.getRightHandSide(ignoreConstraint=True)
803 self.getOperator()
804 else:
805 self.getDomain().addPDEToSystem(self.__getFreshOperator(),self.__getFreshRightHandSide(), \
806 self.getCoefficient("A"), \
807 self.getCoefficient("B"), \
808 self.getCoefficient("C"), \
809 self.getCoefficient("D"), \
810 self.getCoefficient("X"), \
811 self.getCoefficient("Y"), \
812 self.getCoefficient("d"), \
813 self.getCoefficient("y"), \
814 self.getCoefficient("d_contact"), \
815 self.getCoefficient("y_contact"))
816 self.__operator_isValid=True
817 self.__righthandside_isValid=True
818 self.__applyConstraint()
819 self.__copyConstraint(self.__righthandside)
820 elif not self.__operator_isValid:
821 self.getOperator()
822 elif not self.__righthandside_isValid:
823 self.getRightHandSide()
824 return (self.__operator,self.__righthandside)
825
826 def solve(self,**options):
827 """
828 @brief solve the PDE
829
830 @param options
831 """
832 mat,f=self.getSystem()
833 if self.isUsingLumping():
834 out=f/mat
835 self.__copyConstraint(out)
836 else:
837 options[util.TOLERANCE_KEY]=self.getTolerance()
838 options[util.METHOD_KEY]=self.getSolverMethod()
839 options[util.SYMMETRY_KEY]=self.isSymmetric()
840 if self.debug() : print "PDE Debug: solver options: ",options
841 out=mat.solve(f,options)
842 return out
843
844 def getSolution(self,**options):
845 """
846 @brief returns the solution of the PDE
847
848 @param options
849 """
850 if not self.__solution_isValid:
851 if self.debug() : print "PDE Debug: PDE is resolved."
852 self.__solution=self.solve(**options)
853 self.__solution_isValid=True
854 return self.__solution
855 #============ some serivice functions =====================================================
856 def getDomain(self):
857 """
858 @brief returns the domain of the PDE
859 """
860 return self.__domain
861
862 def getDim(self):
863 """
864 @brief returns the spatial dimension of the PDE
865 """
866 return self.getDomain().getDim()
867
868 def getNumEquations(self):
869 """
870 @brief returns the number of equations
871 """
872 if self.__numEquations>0:
873 return self.__numEquations
874 else:
875 raise ValueError,"Number of equations is undefined. Please specify argument numEquations."
876
877 def getNumSolutions(self):
878 """
879 @brief returns the number of unknowns
880 """
881 if self.__numSolutions>0:
882 return self.__numSolutions
883 else:
884 raise ValueError,"Number of solution is undefined. Please specify argument numSolutions."
885
886
887 def checkSymmetry(self):
888 """
889 @brief returns if the Operator is symmetric. This is a very expensive operation!!! The symmetry flag is not altered.
890 """
891 raise SystemError,"checkSymmetry is not implemented yet"
892
893 return None
894
895 def getFlux(self,u):
896 """
897 @brief returns the flux J_ij for a given u
898
899 J_ij=A_{ijkl}u_{k,l}+B_{ijk}u_k-X_{ij}
900
901 @param u argument of the operator
902
903 """
904 raise SystemError,"getFlux is not implemented yet"
905 return None
906
907 def applyOperator(self,u):
908 """
909 @brief applies the operator of the PDE to a given solution u in weak from
910
911 @param u argument of the operator
912
913 """
914 return self.getOperator()*escript.Data(u,self.getFunctionSpaceForSolution())
915
916 def getResidual(self,u):
917 """
918 @brief return the residual of u in the weak from
919
920 @param u
921 """
922 return self.applyOperator(u)-self.getRightHandSide()
923
924 class Poisson(LinearPDE):
925 """
926 @brief Class to define a Poisson equstion problem:
927
928 class to define a linear PDE of the form
929
930 -u_{,jj} = f
931
932 with boundary conditons:
933
934 n_j*u_{,j} = 0
935
936 and constraints:
937
938 u=0 where q>0
939
940 """
941
942 def __init__(self,domain=None,f=escript.Data(),q=escript.Data()):
943 LinearPDE.__init__(self,domain=identifyDomain(domain,{"f":f, "q":q}))
944 self._setValue(A=numarray.identity(self.getDomain().getDim()))
945 self.setSymmetryOn()
946 self.setValue(f,q)
947
948 def setValue(self,f=escript.Data(),q=escript.Data()):
949 self._setValue(Y=f,q=q)
950
951
952 # $Log$
953 # Revision 1.3 2004/12/17 07:43:10 jgs
954 # *** empty log message ***
955 #
956 # Revision 1.1.2.3 2004/12/16 00:12:34 gross
957 # __init__ of LinearPDE does not accept any coefficients anymore
958 #
959 # Revision 1.1.2.2 2004/12/14 03:55:01 jgs
960 # *** empty log message ***
961 #
962 # Revision 1.1.2.1 2004/12/12 22:53:47 gross
963 # linearPDE has been renamed LinearPDE
964 #
965 # Revision 1.1.1.1.2.7 2004/12/07 10:13:08 gross
966 # GMRES added
967 #
968 # Revision 1.1.1.1.2.6 2004/12/07 03:19:50 gross
969 # options for GMRES and PRES20 added
970 #
971 # Revision 1.1.1.1.2.5 2004/12/01 06:25:15 gross
972 # some small changes
973 #
974 # Revision 1.1.1.1.2.4 2004/11/24 01:50:21 gross
975 # Finley solves 4M unknowns now
976 #
977 # Revision 1.1.1.1.2.3 2004/11/15 06:05:26 gross
978 # poisson solver added
979 #
980 # Revision 1.1.1.1.2.2 2004/11/12 06:58:15 gross
981 # a lot of changes to get the linearPDE class running: most important change is that there is no matrix format exposed to the user anymore. the format is chosen by the Domain according to the solver and symmetry
982 #
983 # Revision 1.1.1.1.2.1 2004/10/28 22:59:22 gross
984 # finley's RecTest.py is running now: problem in SystemMatrixAdapater fixed
985 #
986 # Revision 1.1.1.1 2004/10/26 06:53:56 jgs
987 # initial import of project esys2
988 #
989 # Revision 1.3.2.3 2004/10/26 06:43:48 jgs
990 # committing Lutz's and Paul's changes to brach jgs
991 #
992 # Revision 1.3.4.1 2004/10/20 05:32:51 cochrane
993 # Added incomplete Doxygen comments to files, or merely put the docstrings that already exist into Doxygen form.
994 #
995 # Revision 1.3 2004/09/23 00:53:23 jgs
996 # minor fixes
997 #
998 # Revision 1.1 2004/08/28 12:58:06 gross
999 # SimpleSolve is not running yet: problem with == of functionsspace
1000 #
1001 #

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.26