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
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-20 13:03 +0000
1from __future__ import division
3"""Block operations for linear algebra.
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.
10In addition, methods are injected into dolfin.Matrix / dolfin.Vector as
11needed.
12"""
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
24def _init():
25 import dolfin
26 from .object_pool import vec_pool, store_args_ref
27 from .block_base import block_container
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
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
37 def inject_matrix_method(name, meth):
38 setattr(dolfin.Matrix, name, meth)
39 setattr(dolfin.PETScMatrix, name, meth)
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)
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)
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))
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)
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
83 inject_matrix_method('create_vec', vec_pool(create_vec))
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__)
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)
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)
103 def T(self):
104 from .block_compose import block_transpose
105 return block_transpose(self)
106 inject_matrix_method('T', property(T))
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
117_init()