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
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-20 13:03 +0000
1from __future__ import division
3from builtins import str
4from builtins import map
5from builtins import object
6import numpy
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)
22 def __rmul__(self, other):
23 from .block_compose import block_mul
24 return block_mul(other, self)
26 def __neg__(self):
27 from .block_compose import block_mul
28 return block_mul(-1, self)
30 def __add__(self, other):
31 from .block_compose import block_add
32 return block_add(self, other)
34 def __radd__(self, other):
35 from .block_compose import block_add
36 return block_add(other, self)
38 def __sub__(self, other):
39 from .block_compose import block_sub
40 return block_sub(self, other)
42 def __rsub__(self, other):
43 from .block_compose import block_sub
44 return block_sub(other, self)
46 @property
47 def T(self):
48 from .block_compose import block_transpose
49 return block_transpose(self)
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)
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
68 self.blocks = numpy.ndarray(mn, dtype=object)
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
82 # Assign
83 self.blocks[:] = blocks
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]
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)))