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

77 statements  

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

1from __future__ import division 

2 

3from builtins import str 

4from builtins import map 

5from builtins import object 

6import numpy 

7 

8class block_base(object): 

9 """Base class for (block) operators. Defines algebraic operations that 

10 defer actual calculations to a later time if the RHS is not a 

11 vector. Classes that inherit from block_base should at least define a 

12 matvec(self, other) method. 

13 """ 

14 def __mul__(self, other): 

15 from .block_compose import block_mul 

16 from .block_vec import block_vec 

17 from dolfin import GenericVector 

18 if not isinstance(other, (block_vec, GenericVector)): 

19 return block_mul(self, other) 

20 return self.matvec(other) 

21 

22 def __rmul__(self, other): 

23 from .block_compose import block_mul 

24 return block_mul(other, self) 

25 

26 def __neg__(self): 

27 from .block_compose import block_mul 

28 return block_mul(-1, self) 

29 

30 def __add__(self, other): 

31 from .block_compose import block_add 

32 return block_add(self, other) 

33 

34 def __radd__(self, other): 

35 from .block_compose import block_add 

36 return block_add(other, self) 

37 

38 def __sub__(self, other): 

39 from .block_compose import block_sub 

40 return block_sub(self, other) 

41 

42 def __rsub__(self, other): 

43 from .block_compose import block_sub 

44 return block_sub(other, self) 

45 

46 @property 

47 def T(self): 

48 from .block_compose import block_transpose 

49 return block_transpose(self) 

50 

51 def __pow__(self, other): 

52 p = int(other) 

53 if p != other or p < 0: 

54 raise ValueError("power must be a positive integer") 

55 if p == 0: 

56 return 1 

57 if p == 1: 

58 return self 

59 return self * pow(self, other-1) 

60 

61class block_container(block_base): 

62 """Base class for block containers: block_mat and block_vec. 

63 """ 

64 def __init__(self, mn, blocks): 

65 import dolfin 

66 from .block_util import flatten 

67 

68 self.blocks = numpy.ndarray(mn, dtype=object) 

69 

70 # Hack: Set __len__ to a function always returning 0. This stops numpy 

71 # from requesting elements via __getitem__, which fails in parallel 

72 # (due to non-zero-based numbering). 

73 orig_len_func = {} 

74 for el in flatten(blocks): 

75 if isinstance(el, dolfin.Matrix): 

76# if isinstance(el, dolfin.GenericTensor): 

77 tp = type(el) 

78 if not tp in orig_len_func: 

79 orig_len_func[tp] = getattr(tp, '__len__', None) 

80 tp.__len__ = lambda s:0 80 ↛ exitline 80 didn't run the lambda on line 80

81 

82 # Assign 

83 self.blocks[:] = blocks 

84 

85 # Reset __len__ to what it was before the hack above 

86 for tp in list(orig_len_func.keys()): 

87 if orig_len_func[tp] is None: 87 ↛ 90line 87 didn't jump to line 90, because the condition on line 87 was never false

88 delattr(tp, '__len__') 

89 else: 

90 tp.__len__ = orig_len_func[tp] 

91 

92 def __setitem__(self, key, val): 

93 self.blocks[key] = val 

94 def __getitem__(self, key): 

95 try: 

96 return self.blocks[key] 

97 except (IndexError, e): 

98 raise IndexError(str(e) + ' at ' + str(key) + ' -- incompatible block structure') 

99 def __len__(self): 

100 return len(self.blocks) 

101 def __iter__(self): 

102 return self.blocks.__iter__() 

103 def __str__(self): 

104 try: 

105 return '<%s %s:\n%s>'%(self.__class__.__name__, 

106 'x'.join(map(str, self.blocks.shape)), 

107 str(self.blocks)) 

108 except: 

109 # some weird numpy-dolfin interaction going on 

110 return '<%s %s>:\n{%s}'%(self.__class__.__name__, 

111 'x'.join(map(str, self.blocks.shape)), 

112 ', '.join(map(str, self.blocks)))