Coverage for /usr/share/miniconda3/envs/dolfin/lib/python3.8/site-packages/block/__init__.py: 88%

69 statements  

« prev     ^ index     » next       coverage.py v7.2.1, created at 2023-03-20 13:03 +0000

1from __future__ import division 

2 

3"""Block operations for linear algebra. 

4 

5To make this work, all operators should define at least a __mul__(self, other) 

6method, which either does its thing (typically if isinstance(other, 

7(block_vec, GenericVector))), or returns a block_mul(self, other) object which defers the 

8action until there is a proper vector to work on. 

9 

10In addition, methods are injected into dolfin.Matrix / dolfin.Vector as 

11needed. 

12""" 

13 

14from .helpers import supports_mpi 

15from .block_mat import block_mat 

16from .block_vec import block_vec 

17from .block_compose import block_mul, block_add, block_sub, block_transpose 

18from .block_transform import block_kronecker, block_simplify, block_collapse 

19from .block_bc import block_bc 

20from .block_assemble import block_assemble, block_symmetric_assemble 

21from .block_util import issymmetric 

22from .testing import check_expected 

23 

24def _init(): 

25 import dolfin 

26 from .object_pool import vec_pool, store_args_ref 

27 from .block_base import block_container 

28 

29 # To make stuff like L=C*B work when C and B are type dolfin.Matrix, we inject 

30 # methods into dolfin.(Generic)Matrix 

31 

32 def check_type(obj1, obj2): 

33 if isinstance(obj2, block_container): 33 ↛ 34line 33 didn't jump to line 34, because the condition on line 33 was never true

34 raise TypeError('cannot apply dolfin operators on block containers:\n\t%s\nand\n\t%s'%(obj1,obj2)) 

35 return True 

36 

37 def inject_matrix_method(name, meth): 

38 setattr(dolfin.Matrix, name, meth) 

39 setattr(dolfin.PETScMatrix, name, meth) 

40 

41 

42 def inject_vector_method(name, meth): 

43 setattr(dolfin.GenericVector, name, meth) 

44 setattr(dolfin.Vector, name, meth) 

45 setattr(dolfin.PETScVector, name, meth) 

46 

47 def wrap_mul(self, other): 

48 if isinstance(other, dolfin.GenericVector): 

49 ret = self.create_vec(dim=0) 

50 self.mult(other, ret) 

51 return ret 

52 else: 

53 check_type(self, other) 

54 return block_mul(self, other) 

55 inject_matrix_method('__mul__', wrap_mul) 

56 

57 inject_matrix_method('__add__', lambda self, other: check_type(self, other) and block_add(self, other)) 

58 inject_matrix_method('__sub__', lambda self, other: check_type(self, other) and block_sub(self, other)) 58 ↛ exitline 58 didn't run the lambda on line 58

59 inject_matrix_method('__rmul__', lambda self, other: check_type(self, other) and block_mul(other, self)) 

60 inject_matrix_method('__radd__', lambda self, other: check_type(self, other) and block_add(other, self)) 

61 #inject_matrix_method('__rsub__', lambda self, other: check_type(self, other) and block_sub(other, self)) 

62 inject_matrix_method('__neg__', lambda self : block_mul(-1, self)) 

63 

64 # Inject a new transpmult() method that returns the result vector (instead of output parameter) 

65 old_transpmult = dolfin.Matrix.transpmult 

66 def transpmult(self, x, y=None): 

67 check_type(self, x) 

68 if y is None: 68 ↛ 70line 68 didn't jump to line 70, because the condition on line 68 was never false

69 y = self.create_vec(dim=1) 

70 old_transpmult(self, x, y) 

71 return y 

72 inject_matrix_method('transpmult', transpmult) 

73 

74 # Inject a create() method that returns the new vector (instead of resize() which uses out parameter) 

75 def create_vec(self, dim=1): 

76 """Create a vector that is compatible with the matrix. Given A*x=b: 

77 If dim==0, the vector can be used for b (layout like the rows of A); 

78 if dim==1, the vector can be used for x (layout like the columns of A).""" 

79 vec = dolfin.Vector() 

80 self.init_vector(vec, dim) 

81 return vec 

82 

83 inject_matrix_method('create_vec', vec_pool(create_vec)) 

84 

85 # HACK: The problem is that create_vec uses a pool of free vectors, but the internal 

86 # (shared_ptr) reference in Function is not visible in Python. This creates an explicit 

87 # Python-side reference to the Vector, so it's not considered re-usable too soon. 

88 dolfin.Function.__init__ = store_args_ref(dolfin.Function.__init__) 

89 

90 # For the Trilinos stuff, it's much nicer if down_cast is a method on the 

91 # object. FIXME: Follow new dolfin naming? Invent our own? 

92 if hasattr(dolfin, 'as_backend_type'): 92 ↛ 97line 92 didn't jump to line 97, because the condition on line 92 was never false

93 inject_matrix_method('down_cast', dolfin.as_backend_type) 

94 inject_vector_method('down_cast', dolfin.as_backend_type) 

95 else: 

96 # Old name (before Sept-2012) 

97 inject_matrix_method('down_cast', dolfin.down_cast) 

98 inject_vector_method('down_cast', dolfin.down_cast) 

99 

100 if not hasattr(dolfin.Matrix, 'init_vector'): 100 ↛ 101line 100 didn't jump to line 101, because the condition on line 100 was never true

101 inject_matrix_method('init_vector', dolfin.Matrix.resize) 

102 

103 def T(self): 

104 from .block_compose import block_transpose 

105 return block_transpose(self) 

106 inject_matrix_method('T', property(T)) 

107 

108 # Make sure PyTrilinos is imported somewhere, otherwise the types from 

109 # e.g. Matrix.down_cast aren't recognised (if using Epetra backend). 

110 # Not tested, but assuming the same is true for the PETSc backend. 

111 for backend in ['PyTrilinos', 'petsc4py']: 

112 try: 

113 __import__(backend) 

114 except ImportError: 

115 pass 

116 

117_init()