1414"""
1515
1616import functools
17+ import itertools
1718import typing
1819
1920from petsc4py import PETSc
2223import numpy .typing as npt
2324
2425import dolfinx
25- from dolfinx .la import IndexMap , Vector
26+ from dolfinx .fem .function import FunctionSpace
27+ from dolfinx .la import Vector
2628
2729assert dolfinx .has_petsc4py
2830
2931__all__ = ["assign" , "create_vector" , "create_vector_wrap" ]
3032
3133
32- def create_vector (index_map : IndexMap , bs : int ) -> PETSc .Vec : # type: ignore[name-defined]
33- """Create a distributed PETSc vector.
34-
35- Args:
36- index_map: Index map that describes the size and parallel layout of
37- the vector to create.
38- bs: Block size of the vector.
39-
40- Returns:
41- PETSc Vec object.
42- """
43- ghosts = index_map .ghosts .astype (PETSc .IntType ) # type: ignore[attr-defined]
44- size = (index_map .size_local * bs , index_map .size_global * bs )
45- return PETSc .Vec ().createGhost (ghosts , size = size , bsize = bs , comm = index_map .comm ) # type: ignore
46-
47-
4834def create_vector_wrap (x : Vector ) -> PETSc .Vec : # type: ignore[name-defined]
4935 """Wrap a distributed DOLFINx vector as a PETSc vector.
5036
@@ -63,6 +49,90 @@ def create_vector_wrap(x: Vector) -> PETSc.Vec: # type: ignore[name-defined]
6349 )
6450
6551
52+ def create_vector (
53+ V : typing .Union [list [FunctionSpace ]],
54+ kind : typing .Optional [str ] = None ,
55+ ) -> PETSc .Vec :
56+ """Create a PETSc vector that is compatible with a Functionspace
57+ or a list of Functionspace(s).
58+
59+ Three cases are supported:
60+
61+ 1. For a single functionspace ``V``, if ``kind`` is ``None`` or is
62+ ``PETSc.Vec.Type.MPI``, a ghosted PETSc vector which is
63+ compatible with ``V`` is created.
64+
65+ 2. If ``V=[V_0, ..., V_n]`` is a sequence of function spaces and ``kind`` is ``None``
66+ or is ``PETSc.Vec.Type.MPI``, a ghosted PETSc vector which is
67+ compatible with ``V`` is created. The created vector ``b`` is
68+ initialized such that on each MPI process ``b = [b_0, b_1, ...,
69+ b_n, b_0g, b_1g, ..., b_ng]``, where ``b_i`` are the entries
70+ associated with the 'owned' degrees-of-freedom for ``V[i]`` and
71+ ``b_ig`` are the 'unowned' (ghost) entries for ``V[i]``.
72+
73+ For this case, the returned vector has an attribute ``_blocks``
74+ that holds the local offsets into ``b`` for the (i) owned and
75+ (ii) ghost entries for each ``V[i]``. It can be accessed by
76+ ``b.getAttr("_blocks")``. The offsets can be used to get views
77+ into ``b`` for blocks, e.g.::
78+
79+ >>> offsets0, offsets1, = b.getAttr("_blocks")
80+ >>> offsets0
81+ (0, 12, 28)
82+ >>> offsets1
83+ (28, 32, 35)
84+ >>> b0_owned = b.array[offsets0[0]:offsets0[1]]
85+ >>> b0_ghost = b.array[offsets1[0]:offsets1[1]]
86+ >>> b1_owned = b.array[offsets0[1]:offsets0[2]]
87+ >>> b1_ghost = b.array[offsets1[1]:offsets1[2]]
88+
89+ 3. If `V=[V_0, ..., V_n]`` is a sequence of function space and ``kind`` is
90+ ``PETSc.Vec.Type.NEST``, a PETSc nested vector (a 'nest' of
91+ ghosted PETSc vectors) which is compatible with ``V`` is created.
92+
93+ Args:
94+ V: Functionspace or a sequence of functionspaces.
95+ kind: PETSc vector type (``VecType``) to create.
96+
97+ Returns:
98+ A PETSc vector with a layout that is compatible with ````. The
99+ vector is not initialised to zero.
100+ """
101+ if len (V ) == 1 :
102+ # Single space case
103+ index_map = V [0 ].dofmap .index_map
104+ bs = V [0 ].dofmap .index_map_bs
105+ ghosts = index_map .ghosts .astype (PETSc .IntType ) # type: ignore[attr-defined]
106+ size = (index_map .size_local * bs , index_map .size_global * bs )
107+ return PETSc .Vec ().createGhost (ghosts , size = size , bsize = bs , comm = index_map .comm ) # type: ignore
108+
109+ maps = [(_V .dofmaps (0 ).index_map , _V .dofmaps (0 ).index_map_bs ) for _V in V ]
110+
111+ if kind is None or kind == PETSc .Vec .Type .MPI :
112+ off_owned = tuple (
113+ itertools .accumulate (maps , lambda off , m : off + m [0 ].size_local * m [1 ], initial = 0 )
114+ )
115+ off_ghost = tuple (
116+ itertools .accumulate (
117+ maps , lambda off , m : off + m [0 ].num_ghosts * m [1 ], initial = off_owned [- 1 ]
118+ )
119+ )
120+
121+ b = dolfinx .cpp .fem .petsc .create_vector_block (maps )
122+ b .setAttr ("_blocks" , (off_owned , off_ghost ))
123+ return b
124+
125+ elif kind == PETSc .Vec .Type .NEST :
126+ return dolfinx .cpp .fem .petsc .create_vector_nest (maps )
127+
128+ else :
129+ raise NotImplementedError (
130+ "Vector type must be specified for blocked/nested assembly."
131+ f"Vector type '{ kind } ' not supported."
132+ "Did you mean 'nest' or 'mpi'?"
133+ )
134+
135+
66136@functools .singledispatch
67137def assign (x0 : typing .Union [npt .NDArray [np .inexact ], list [npt .NDArray [np .inexact ]]], x1 : PETSc .Vec ): # type: ignore
68138 """Assign ``x0`` values to a PETSc vector ``x1``.
0 commit comments