Distributed vector spaces and matrix storage formats
PETSc vectors are distributed across the communicator with each process owning a contiguous block of rows. The most common case is for all the parts to be the same size, but that is not necessary. Any partition of the $N$ entries into $P$ contiguous parts (some possibly empty) with the parts labeled sequentially is valid. The Mat class represents a linear transformation between two finite dimensional vector spaces, $A: X \to Y$. The spaces $X$ and $Y$ may be different (even different sizes), though Krylov methods and most linear solvers require that $X = Y$. There are routines for looking at the ownership range of the current process:
The storage format used by PETSc MPI*AIJ matrices distributes the entries according to ownership of the range space $Y$. In this model, there are generally some entries of the domain $X$ that affect the owned part of $Y$. To be precise, let $X_i \subset X$ be the part of the domain space $X$ that is owned by process (MPI rank) $i$ and similarly for $Y_i \subset Y$. The "diagonal block" of the matrix owned by rank $i$ is exactly the effect of $X_i$ on $Y_i$. When performing multiplication, the part of a vector in $X_i$ is available locally without any communication. The "off-diagonal block" represents the effect of $X \setminus X_i$ on $Y_i$, which cannot be applied without communicating entries. The operation $y \gets A x$ is computed as
- Start communicating off-process entries of $x$ to $x_i^{\text{off}}$.
- Apply the diagonal block of the matrix $y_i \gets A_i^{\text{diag}} x_i$.
- Finish communicating off-process entries.
- Add the action of the off-diagonal block $y_i \gets y_i + A_i^{\text{off}} x_i^{\text{off}}$
Geometrically, the off-diagonal part corresponds to the influence of the "ghost points" on the subdomain.
Preallocation
Since the diagonal part $A_i^{\text{diag}}$ is stored separately from $A_i^{\text{off}}$, we need separate preallocation information to avoid dynamic data structures. This can be done by providing one parameter indicating the maximum number of nonzeros in any row (*_nz) or by providing an array indicating the number of nonzeros in each row (*_nnz). Note that rows corresponding to "interior" points will generally have no nonzero entries in the off-diagonal part.
As for ex2.c, there are indeed never more than 5 nonzeros per row of the matrix, of which at least one (the diagonal entry) must fall in the diagonal block. Therefore it would have been safe to pass o_nz=4. Note that this extreme case o_nz=4 is only realized by this example for a single-point subdomain.