From 961dc048da4b778be3fc9ede0b3405c7cbe84275 Mon Sep 17 00:00:00 2001
From: Henry Weller <http://cfd.direct>
Date: Tue, 22 Mar 2016 14:09:24 +0000
Subject: [PATCH] Matrix: Added support for extracting and assigning blocks

The blocks may be specified directly in terms of the size and location in the
parent matrix or with the size obtained from a template specified
VectorSpace or MatrixSpace type.
---
 src/OpenFOAM/matrices/Matrix/Matrix.C  | 467 +++++++++++++++++++++++--
 src/OpenFOAM/matrices/Matrix/Matrix.H  | 301 ++++++++++++++--
 src/OpenFOAM/matrices/Matrix/MatrixI.H | 332 +++++++++++++++++-
 3 files changed, 1044 insertions(+), 56 deletions(-)

diff --git a/src/OpenFOAM/matrices/Matrix/Matrix.C b/src/OpenFOAM/matrices/Matrix/Matrix.C
index 6ccd1c79e52..808e00b86c2 100644
--- a/src/OpenFOAM/matrices/Matrix/Matrix.C
+++ b/src/OpenFOAM/matrices/Matrix/Matrix.C
@@ -37,22 +37,28 @@ void Foam::Matrix<Form, Type>::allocate()
 }
 
 
-// * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 template<class Form, class Type>
-Foam::Matrix<Form, Type>::~Matrix()
+Foam::Matrix<Form, Type>::Matrix(const label m, const label n)
+:
+    nRows_(m),
+    nCols_(n),
+    v_(NULL)
 {
-    if (v_)
+    if (nRows_ < 0 || nCols_ < 0)
     {
-        delete[] v_;
+        FatalErrorInFunction
+            << "Bad m, n " << nRows_ << ", " << nCols_
+            << abort(FatalError);
     }
-}
 
+    allocate();
+}
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 template<class Form, class Type>
-Foam::Matrix<Form, Type>::Matrix(const label m, const label n)
+Foam::Matrix<Form, Type>::Matrix(const label m, const label n, const zero)
 :
     nRows_(m),
     nCols_(n),
@@ -66,6 +72,15 @@ Foam::Matrix<Form, Type>::Matrix(const label m, const label n)
     }
 
     allocate();
+
+    if (v_)
+    {
+        const label mn = size();
+        for (label i=0; i<mn; i++)
+        {
+            v_[i] = Zero;
+        }
+    }
 }
 
 
@@ -79,7 +94,7 @@ Foam::Matrix<Form, Type>::Matrix(const label m, const label n, const Type& a)
     if (nRows_ < 0 || nCols_ < 0)
     {
         FatalErrorInFunction
-            << "bad m, n " << nRows_ << ", " << nCols_
+            << "Bad m, n " << nRows_ << ", " << nCols_
             << abort(FatalError);
     }
 
@@ -96,6 +111,24 @@ Foam::Matrix<Form, Type>::Matrix(const label m, const label n, const Type& a)
 }
 
 
+template<class Form, class Type>
+inline Foam::Matrix<Form, Type>::Matrix(const mType::Block& block)
+:
+    nRows_(block.m()),
+    nCols_(block.n())
+{
+    allocate();
+
+    for (label i=0; i<nRows_; i++)
+    {
+        for (label j=0; j<nCols_; j++)
+        {
+            (*this)(i,j) = block(i,j);
+        }
+    }
+}
+
+
 template<class Form, class Type>
 Foam::Matrix<Form, Type>::Matrix(const Matrix<Form, Type>& a)
 :
@@ -116,6 +149,20 @@ Foam::Matrix<Form, Type>::Matrix(const Matrix<Form, Type>& a)
 }
 
 
+// * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * * //
+
+template<class Form, class Type>
+Foam::Matrix<Form, Type>::~Matrix()
+{
+    if (v_)
+    {
+        delete[] v_;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
 template<class Form, class Type>
 void Foam::Matrix<Form, Type>::clear()
 {
@@ -146,6 +193,26 @@ void Foam::Matrix<Form, Type>::transfer(Matrix<Form, Type>& a)
 }
 
 
+template<class Form, class Type>
+void Foam::Matrix<Form, Type>::setSize(const label m, const label n)
+{
+    mType newMatrix(m, n, Zero);
+
+    label minM = min(m, nRows_);
+    label minN = min(n, nCols_);
+
+    for (label i=0; i<minM; i++)
+    {
+        for (label j=0; j<minN; j++)
+        {
+            newMatrix(i, j) = (*this)(i, j);
+        }
+    }
+
+    transfer(newMatrix);
+}
+
+
 template<class Form, class Type>
 Form Foam::Matrix<Form, Type>::T() const
 {
@@ -164,29 +231,57 @@ Form Foam::Matrix<Form, Type>::T() const
 }
 
 
-// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+template<class Form, class Type>
+Foam::Matrix<Form, Type>::ConstBlock::operator Field<cmptType>() const
+{
+    if (nCols_ != 1)
+    {
+        FatalErrorInFunction
+            << "Number of columns " << nCols_ << " != 1"
+            << abort(FatalError);
+    }
+
+    Field<cmptType> f(nRows_);
+
+    forAll(f, i)
+    {
+        f[i] = operator()(i, 0);
+    }
+
+    return f;
+}
+
 
 template<class Form, class Type>
-void Foam::Matrix<Form, Type>::operator=(const Type& t)
+Foam::Matrix<Form, Type>::Block::operator Field<cmptType>() const
 {
-    if (v_)
+    if (nCols_ != 1)
     {
-        const label mn = size();
-        for (label i=0; i<mn; i++)
-        {
-            v_[i] = t;
-        }
+        FatalErrorInFunction
+            << "Number of columns " << nCols_ << " != 1"
+            << abort(FatalError);
+    }
+
+    Field<cmptType> f(nRows_);
+
+    forAll(f, i)
+    {
+        f[i] = operator()(i, 0);
     }
+
+    return f;
 }
 
 
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
 template<class Form, class Type>
 void Foam::Matrix<Form, Type>::operator=(const Matrix<Form, Type>& a)
 {
     if (this == &a)
     {
         FatalErrorInFunction
-            << "attempted assignment to self"
+            << "Attempted assignment to self"
             << abort(FatalError);
     }
 
@@ -209,6 +304,247 @@ void Foam::Matrix<Form, Type>::operator=(const Matrix<Form, Type>& a)
 }
 
 
+template<class Form, class Type>
+void Foam::Matrix<Form, Type>::operator=(const mType::Block& block)
+{
+    for (label i=0; i<nRows_; i++)
+    {
+        for (label j=0; j<nCols_; j++)
+        {
+            (*this)(i,j) = block(i,j);
+        }
+    }
+}
+
+
+template<class Form, class Type>
+void Foam::Matrix<Form, Type>::Block::operator=(const Block& block)
+{
+    if (this != &block)
+    {
+        if (nRows_ != block.m() || nCols_ != block.n())
+        {
+            FatalErrorInFunction
+                << "Attempt to assign blocks of different sizes: "
+                << nRows_ << "x" << nCols_ << " != "
+                << block.m() << "x" << block.n()
+                << abort(FatalError);
+        }
+
+        for (label i=0; i<nRows_; i++)
+        {
+            for (label j=0; j<nCols_; j++)
+            {
+                (*this)(i, j) = block(i, j);
+            }
+        }
+    }
+}
+
+
+template<class Form, class Type>
+void Foam::Matrix<Form, Type>::Block::operator=(const ConstBlock& block)
+{
+    if (this != &block)
+    {
+        if (nRows_ != block.m() || nCols_ != block.n())
+        {
+            FatalErrorInFunction
+                << "Attempt to assign blocks of different sizes: "
+                << nRows_ << "x" << nCols_ << " != "
+                << block.m() << "x" << block.n()
+                << abort(FatalError);
+        }
+
+        for (label i=0; i<nRows_; i++)
+        {
+            for (label j=0; j<nCols_; j++)
+            {
+                (*this)(i, j) = block(i, j);
+            }
+        }
+    }
+}
+
+
+template<class Form, class Type>
+void Foam::Matrix<Form, Type>::Block::operator=(const mType& block)
+{
+    if (nRows_ != block.m() || nCols_ != block.n())
+    {
+        FatalErrorInFunction
+            << "Attempt to assign blocks of different sizes: "
+            << nRows_ << "x" << nCols_ << " != "
+            << block.m() << "x" << block.n()
+            << abort(FatalError);
+    }
+
+    for (label i=0; i<nRows_; i++)
+    {
+        for (label j=0; j<nCols_; j++)
+        {
+            (*this)(i, j) = block(i, j);
+        }
+    }
+}
+
+
+template<class Form, class Type>
+void Foam::Matrix<Form, Type>::operator=(const Type& t)
+{
+    if (v_)
+    {
+        const label mn = size();
+        for (label i=0; i<mn; i++)
+        {
+            v_[i] = t;
+        }
+    }
+}
+
+
+template<class Form, class Type>
+void Foam::Matrix<Form, Type>::operator=(const zero)
+{
+    if (v_)
+    {
+        const label mn = size();
+        for (label i=0; i<mn; i++)
+        {
+            v_[i] = Zero;
+        }
+    }
+}
+
+
+template<class Form, class Type>
+template
+<
+    template<class, Foam::direction, Foam::direction> class MSBlock,
+    class SubTensor,
+    Foam::direction BRowStart,
+    Foam::direction BColStart
+>
+void Foam::Matrix<Form, Type>::Block::operator=
+(
+    const MSBlock<SubTensor, BRowStart, BColStart>& block
+)
+{
+    if (nRows_ != block.nRows || nCols_ != block.nCols)
+    {
+        FatalErrorInFunction
+            << "Attempt to assign blocks of different sizes: "
+            << nRows_ << "x" << nCols_ << " != "
+            << block.nRows << "x" << block.nCols
+            << abort(FatalError);
+    }
+
+    for (direction i=0; i<nRows_; ++i)
+    {
+        for (direction j=0; j<nCols_; ++j)
+        {
+            operator()(i, j) = block(i, j);
+        }
+    }
+}
+
+
+template<class Form, class Type>
+template
+<
+    template<class, Foam::direction> class VSBlock,
+    class SubVector,
+    Foam::direction BStart
+>
+void Foam::Matrix<Form, Type>::Block::operator=
+(
+    const VSBlock<SubVector, BStart>& block
+)
+{
+    if (nRows_ != block.nComponents || nCols_ != 1)
+    {
+        FatalErrorInFunction
+            << "Attempt to assign blocks of different sizes: "
+            << nRows_ << "x" << nCols_ << " != "
+            << block.nComponents << "x" << 1
+            << abort(FatalError);
+    }
+
+    for (direction i=0; i<nRows_; ++i)
+    {
+        operator()(i, 0) = block[i];
+    }
+}
+
+
+template<class Form, class Type>
+template<class MSForm, Foam::direction Nrows, Foam::direction Ncols>
+void Foam::Matrix<Form, Type>::Block::operator=
+(
+    const MatrixSpace<MSForm, cmptType, Nrows, Ncols>& ms
+)
+{
+    if (nRows_ != Nrows || nCols_ != Ncols)
+    {
+        FatalErrorInFunction
+            << "Attempt to assign blocks of different sizes: "
+            << nRows_ << "x" << nCols_ << " != "
+            << Nrows << "x" << Ncols
+            << abort(FatalError);
+    }
+
+    for (label i=0; i<nRows_; i++)
+    {
+        for (label j=0; j<nCols_; j++)
+        {
+            (*this)(i, j) = ms(i, j);
+        }
+    }
+}
+
+
+template<class Form, class Type>
+template<class VSForm, Foam::direction Ncmpts>
+void Foam::Matrix<Form, Type>::Block::operator=
+(
+    const VectorSpace<VSForm, cmptType, Ncmpts>& ms
+)
+{
+    if (nRows_ != Ncmpts || nCols_ != 1)
+    {
+        FatalErrorInFunction
+            << "Attempt to assign blocks of different sizes: "
+            << nRows_ << "x" << nCols_ << " != "
+            << Ncmpts << "x" << 1
+            << abort(FatalError);
+    }
+
+    for (direction i=0; i<Ncmpts; ++i)
+    {
+        operator()(i, 0) = ms[i];
+    }
+}
+
+
+template<class Form, class Type>
+void Foam::Matrix<Form, Type>::Block::operator=(const Field<cmptType>& f)
+{
+    if (nRows_ != f.size() || nCols_ != 1)
+    {
+        FatalErrorInFunction
+            << "Error: cannot assign blocks of different size (left is "
+            << nRows_ << "x" << nCols_ << " != "
+            << f.size() << "x" << 1
+            << abort(FatalError);
+    }
+
+    forAll(f, i)
+    {
+        operator()(i, 0) = f[i];
+    }
+}
+
+
 // * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
 
 template<class Form, class Type>
@@ -234,7 +570,7 @@ const Type& Foam::max(const Matrix<Form, Type>& a)
     else
     {
         FatalErrorInFunction
-            << "matrix is empty"
+            << "Matrix is empty"
             << abort(FatalError);
 
         // Return in error to keep compiler happy
@@ -266,7 +602,7 @@ const Type& Foam::min(const Matrix<Form, Type>& a)
     else
     {
         FatalErrorInFunction
-            << "matrix is empty"
+            << "Matrix is empty"
             << abort(FatalError);
 
         // Return in error to keep compiler happy
@@ -304,7 +640,7 @@ Form Foam::operator+(const Matrix<Form, Type>& a, const Matrix<Form, Type>& b)
     if (a.m() != b.m())
     {
         FatalErrorInFunction
-            << "attempted add matrices with different number of rows: "
+            << "Attempt to add matrices with different number of rows: "
             << a.m() << ", " << b.m()
             << abort(FatalError);
     }
@@ -312,7 +648,7 @@ Form Foam::operator+(const Matrix<Form, Type>& a, const Matrix<Form, Type>& b)
     if (a.n() != b.n())
     {
         FatalErrorInFunction
-            << "attempted add matrices with different number of columns: "
+            << "Attempt to add matrices with different number of columns: "
             << a.n() << ", " << b.n()
             << abort(FatalError);
     }
@@ -339,7 +675,7 @@ Form Foam::operator-(const Matrix<Form, Type>& a, const Matrix<Form, Type>& b)
     if (a.m() != b.m())
     {
         FatalErrorInFunction
-            << "attempted add matrices with different number of rows: "
+            << "Attempt to add matrices with different number of rows: "
             << a.m() << ", " << b.m()
             << abort(FatalError);
     }
@@ -347,7 +683,7 @@ Form Foam::operator-(const Matrix<Form, Type>& a, const Matrix<Form, Type>& b)
     if (a.n() != b.n())
     {
         FatalErrorInFunction
-            << "attempted add matrices with different number of columns: "
+            << "Attempt to add matrices with different number of columns: "
             << a.n() << ", " << b.n()
             << abort(FatalError);
     }
@@ -389,13 +725,55 @@ Form Foam::operator*(const scalar s, const Matrix<Form, Type>& a)
 }
 
 
+template<class Form, class Type>
+Form Foam::operator*(const Matrix<Form, Type>& a, const scalar s)
+{
+    Form sa(a.m(), a.n());
+
+    if (a.m() && a.n())
+    {
+        Type* sav = sa.v();
+        const Type* av = a.v();
+
+        const label mn = a.size();
+        for (label i=0; i<mn; i++)
+        {
+            sav[i] = av[i]*s;
+        }
+    }
+
+    return sa;
+}
+
+
+template<class Form, class Type>
+Form Foam::operator/(const Matrix<Form, Type>& a, const scalar s)
+{
+    Form sa(a.m(), a.n());
+
+    if (a.m() && a.n())
+    {
+        Type* sav = sa.v();
+        const Type* av = a.v();
+
+        const label mn = a.size();
+        for (label i=0; i<mn; i++)
+        {
+            sav[i] = av[i]/s;
+        }
+    }
+
+    return sa;
+}
+
+
 template<class Form, class Type>
 Form Foam::operator*(const Matrix<Form, Type>& a, const Matrix<Form, Type>& b)
 {
     if (a.n() != b.m())
     {
         FatalErrorInFunction
-            << "attempted to multiply incompatible matrices:" << nl
+            << "Attempt to multiply incompatible matrices:" << nl
             << "Matrix A : " << a.m() << " rows, " << a.n() << " columns" << nl
             << "Matrix B : " << b.m() << " rows, " << b.n() << " columns" << nl
             << "In order to multiply matrices, columns of A must equal "
@@ -405,13 +783,13 @@ Form Foam::operator*(const Matrix<Form, Type>& a, const Matrix<Form, Type>& b)
 
     Form ab(a.m(), b.n(), scalar(0));
 
-    for (label i = 0; i < ab.m(); i++)
+    for (label i=0; i<ab.m(); i++)
     {
-        for (label j = 0; j < ab.n(); j++)
+        for (label j=0; j<ab.n(); j++)
         {
-            for (label l = 0; l < b.m(); l++)
+            for (label k=0; k<b.m(); k++)
             {
-                ab(i, j) += a(i, l)*b(l, j);
+                ab(i, j) += a(i, k)*b(k, j);
             }
         }
     }
@@ -420,6 +798,39 @@ Form Foam::operator*(const Matrix<Form, Type>& a, const Matrix<Form, Type>& b)
 }
 
 
+template<class Form, class Type>
+inline Foam::tmp<Foam::Field<Type>> Foam::operator*
+(
+    const Matrix<Form, Type>& M,
+    const Field<Type>& f
+)
+{
+    if (M.n() != f.size())
+    {
+        FatalErrorInFunction
+            << "Attempt to multiply incompatible matrix and field:" << nl
+            << "Matrix : " << M.m() << " rows, " << M.n() << " columns" << nl
+            << "Field : " << f.size() << " rows" << nl
+            << "In order to multiply a matrix M and field f, "
+               "columns of M must equal rows of f"
+            << abort(FatalError);
+    }
+
+    tmp<Field<Type>> tMf(new Field<Type>(f.size(), Zero));
+    Field<Type>& Mf = tMf.ref();
+
+    for (label i=0; i<M.m(); ++i)
+    {
+        for (label j=0; j<M.n(); ++j)
+        {
+            Mf[i] += M(i, j)*f[j];
+        }
+    }
+
+    return tMf;
+}
+
+
 // * * * * * * * * * * * * * * * *  IOStream operators * * * * * * * * * * * //
 
 #include "MatrixIO.C"
diff --git a/src/OpenFOAM/matrices/Matrix/Matrix.H b/src/OpenFOAM/matrices/Matrix/Matrix.H
index 043b9561aa7..5f905b465bc 100644
--- a/src/OpenFOAM/matrices/Matrix/Matrix.H
+++ b/src/OpenFOAM/matrices/Matrix/Matrix.H
@@ -41,7 +41,9 @@ SourceFiles
 #include "bool.H"
 #include "label.H"
 #include "uLabel.H"
-#include "List.H"
+#include "Field.H"
+#include "MatrixSpace.H"
+#include "zero.H"
 #include "autoPtr.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -87,10 +89,168 @@ class Matrix
 
 public:
 
+    //- Matrix type
+    typedef Matrix<Form, Type> mType;
+
+    //- Component type
+    typedef Type cmptType;
+
+
     // Static Member Functions
 
         //- Return a null Matrix
-        inline static const Matrix<Form, Type>& null();
+        inline static const mType& null();
+
+
+    // Sub-Block Classes
+
+        class ConstBlock
+        {
+            // Private data
+
+                //- Const reference to the parent matrix
+                const mType& matrix_;
+
+                // Block size
+                const label nRows_;
+                const label nCols_;
+
+                // Block location in parent matrix
+                const label rowStart_;
+                const label colStart_;
+
+        public:
+
+            typedef typename mType::cmptType cmptType;
+
+            // Constructors
+
+                //- Construct block for matrix, size and location
+                inline ConstBlock
+                (
+                    const mType& matrix,
+                    const label m,
+                    const label n,
+                    const label mStart,
+                    const label nStart
+                );
+
+
+            // Member Functions
+
+                //- Return the number of rows in the block
+                inline label m() const;
+
+                //- Return the number of columns in the block
+                inline label n() const;
+
+                //- (i, j) const element access operator
+                inline const Type& operator()
+                (
+                    const label i,
+                    const label j
+                ) const;
+
+                //- Convert a column of a matrix to a Field
+                operator Field<Type>() const;
+        };
+
+
+        class Block
+        {
+            // Private data
+
+                //- Reference to the parent matrix
+                mType& matrix_;
+
+                // Block size
+                const label nRows_;
+                const label nCols_;
+
+                // Block location in parent matrix
+                const label rowStart_;
+                const label colStart_;
+
+        public:
+
+            typedef typename mType::cmptType cmptType;
+
+            // Constructors
+
+                //- Construct block for matrix, size and location
+                inline Block
+                (
+                    mType& matrix,
+                    const label m,
+                    const label n,
+                    const label mStart,
+                    const label nStart
+                );
+
+
+            // Member Functions
+
+                //- Return the number of rows in the block
+                inline label m() const;
+
+                //- Return the number of columns in the block
+                inline label n() const;
+
+                //- (i, j) const element access operator
+                inline const Type& operator()
+                (
+                    const label i,
+                    const label j
+                ) const;
+
+                //- (i, j) element access operator
+                inline Type& operator()(const label i, const label j);
+
+                //- Convert a column of a matrix to a Field
+                operator Field<Type>() const;
+
+
+            // Member operators
+
+                //- Assignment to a compatible matrix
+                void operator=(const mType&);
+
+                //- Assignment to a compatible block
+                void operator=(const Block&);
+
+                //- Assignment to a compatible const block
+                void operator=(const ConstBlock&);
+
+                //- Assignment to a compatible MatrixSpace
+                template<class MSForm, direction Nrows, direction Ncols>
+                void operator=(const MatrixSpace<MSForm, Type, Nrows, Ncols>&);
+
+                //- Assignment to a compatible MatrixSpace block
+                template
+                <
+                    template<class, direction, direction> class Block,
+                    class SubTensor,
+                    direction BRowStart,
+                    direction BColStart
+                >
+                void operator=(const Block<SubTensor, BRowStart, BColStart>&);
+
+                //- Assignment to a compatible VectorSpace (column-vector)
+                template<class VSForm, direction Ncmpts>
+                void operator=(const VectorSpace<VSForm, Type, Ncmpts>&);
+
+                //- Assignment to a compatible VectorSpace (column-vector) block
+                template
+                <
+                    template<class, direction> class Block,
+                    class SubVector,
+                    direction BStart
+                >
+                void operator=(const Block<SubVector, BStart>&);
+
+                //- Assignment to a Field (column-vector)
+                void operator=(const Field<Type>&);
+        };
 
 
     // Constructors
@@ -102,17 +262,24 @@ public:
         Matrix(const label m, const label n);
 
         //- Construct with given number of rows and columns
-        //  and value for all elements.
+        //  initializing all elements to zero
+        Matrix(const label m, const label n, const zero);
+
+        //- Construct with given number of rows and columns
+        //  initializing all elements to the given value
         Matrix(const label m, const label n, const Type&);
 
         //- Copy constructor.
-        Matrix(const Matrix<Form, Type>&);
+        Matrix(const mType&);
+
+        //- Construct from a block of another matrix
+        Matrix(const mType::Block&);
 
         //- Construct from Istream.
         Matrix(Istream&);
 
         //- Clone
-        inline autoPtr<Matrix<Form, Type>> clone() const;
+        inline autoPtr<mType> clone() const;
 
 
     //- Destructor
@@ -132,6 +299,64 @@ public:
             //- Return the number of elements in matrix (m*n)
             inline label size() const;
 
+            //- Return element vector of the constant Matrix
+            inline const Type* v() const;
+
+            //- Return element vector of the Matrix
+            inline Type* v();
+
+
+        // Block access
+
+            inline ConstBlock block
+            (
+                const label m,
+                const label n,
+                const label mStart,
+                const label nStart
+            ) const;
+
+            template<class VectorSpace>
+            inline ConstBlock block
+            (
+                const label mStart,
+                const label nStart
+            ) const;
+
+            inline ConstBlock col
+            (
+                const label m,
+                const label rowStart
+            ) const;
+
+            inline ConstBlock col
+            (
+                const label m,
+                const label mStart,
+                const label nStart
+            ) const;
+
+
+            inline Block block
+            (
+                const label m,
+                const label n,
+                const label mStart,
+                const label nStart
+            );
+
+            template<class VectorSpace>
+            inline Block block(const label mStart, const label nStart);
+
+            inline Block col(const label m, const label rowStart);
+
+            inline Block col
+            (
+                const label m,
+                const label mStart,
+                const label nStart
+            );
+
 
         // Check
 
@@ -149,7 +374,10 @@ public:
 
             //- Transfer the contents of the argument Matrix into this Matrix
             //  and annul the argument Matrix.
-            void transfer(Matrix<Form, Type>&);
+            void transfer(mType&);
+
+            //- Resize the matrix preserving the elements
+            void setSize(const label m, const label nCols);
 
 
         //- Return the transpose of the matrix
@@ -158,12 +386,6 @@ public:
 
     // Member operators
 
-        //- Return element vector of the constant Matrix
-        inline const Type* v() const;
-
-        //- Return element vector of the Matrix
-        inline Type* v();
-
         //- Return subscript-checked row of Matrix.
         inline Type* operator[](const label);
 
@@ -177,7 +399,13 @@ public:
         inline Type& operator()(const label i, const label j);
 
         //- Assignment operator. Takes linear time.
-        void operator=(const Matrix<Form, Type>&);
+        void operator=(const mType&);
+
+        //- Assignment to a block of another matrix
+        void operator=(const mType::Block&);
+
+        //- Assignment of all entries to zero
+        void operator=(const zero);
 
         //- Assignment of all entries to the given value
         void operator=(const Type&);
@@ -189,49 +417,78 @@ public:
         friend Istream& operator>> <Form, Type>
         (
             Istream&,
-            Matrix<Form, Type>&
+            mType&
         );
 
         // Write Matrix to Ostream.
         friend Ostream& operator<< <Form, Type>
         (
             Ostream&,
-            const Matrix<Form, Type>&
+            const mType&
         );
 };
 
 
 // Global functions and operators
 
-template<class Form, class Type> const Type& max(const Matrix<Form, Type>&);
-template<class Form, class Type> const Type& min(const Matrix<Form, Type>&);
+template<class Form, class Type>
+const Type& max(const Matrix<Form, Type>&);
+
+template<class Form, class Type>
+const Type& min(const Matrix<Form, Type>&);
 
-template<class Form, class Type> Form operator-(const Matrix<Form, Type>&);
+template<class Form, class Type>
+Form operator-(const Matrix<Form, Type>&);
 
-template<class Form, class Type> Form operator+
+template<class Form, class Type>
+Form operator+
 (
     const Matrix<Form, Type>&,
     const Matrix<Form, Type>&
 );
 
-template<class Form, class Type> Form operator-
+template<class Form, class Type>
+Form operator-
 (
     const Matrix<Form, Type>&,
     const Matrix<Form, Type>&
 );
 
-template<class Form, class Type> Form operator*
+template<class Form, class Type>
+Form operator*
 (
     const scalar,
     const Matrix<Form, Type>&
 );
 
-template<class Form, class Type> Form operator*
+template<class Form, class Type>
+Form operator*
+(
+    const Matrix<Form, Type>&,
+    const scalar
+);
+
+template<class Form, class Type>
+Form operator/
+(
+    const Matrix<Form, Type>&,
+    const scalar
+);
+
+template<class Form, class Type>
+Form operator*
 (
     const Matrix<Form, Type>&,
     const Matrix<Form, Type>&
 );
 
+template<class Form, class Type>
+tmp<Field<Type>> operator*
+(
+    const Matrix<Form, Type>&,
+    const Field<Type>&
+);
+
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
diff --git a/src/OpenFOAM/matrices/Matrix/MatrixI.H b/src/OpenFOAM/matrices/Matrix/MatrixI.H
index 532e9df3f8d..73992f3285d 100644
--- a/src/OpenFOAM/matrices/Matrix/MatrixI.H
+++ b/src/OpenFOAM/matrices/Matrix/MatrixI.H
@@ -42,6 +42,68 @@ clone() const
 }
 
 
+template<class Form, class Type>
+Foam::Matrix<Form, Type>::ConstBlock::ConstBlock
+(
+    const mType& matrix,
+    const label m,
+    const label n,
+    const label mStart,
+    const label nStart
+)
+:
+    matrix_(matrix),
+    nRows_(m),
+    nCols_(n),
+    rowStart_(mStart),
+    colStart_(nStart)
+{
+    #ifdef FULLDEBUG
+    if
+    (
+        rowStart_ + nRows_ > matrix.m()
+     || colStart_ + nCols_ > matrix.n()
+    )
+    {
+        FatalErrorInFunction
+            << "Block addresses outside matrix"
+            << abort(FatalError);
+    }
+    #endif
+}
+
+
+template<class Form, class Type>
+Foam::Matrix<Form, Type>::Block::Block
+(
+    mType& matrix,
+    const label m,
+    const label n,
+    const label mStart,
+    const label nStart
+)
+:
+    matrix_(matrix),
+    nRows_(m),
+    nCols_(n),
+    rowStart_(mStart),
+    colStart_(nStart)
+{
+    #ifdef FULLDEBUG
+    if
+    (
+        rowStart_ + nRows_ > matrix.m()
+     || colStart_ + nCols_ > matrix.n()
+    )
+    {
+        FatalErrorInFunction
+            << "Block addresses outside matrix"
+            << abort(FatalError);
+    }
+    #endif
+}
+
+
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 template<class Form, class Type>
@@ -76,16 +138,16 @@ template<class Form, class Type>
 inline void Foam::Matrix<Form, Type>::checki(const label i) const
 {
     #ifdef FULLDEBUG
-    if (!nRows_)
+    if (!nRows_ || !nCols_)
     {
         FatalErrorInFunction
-            << "attempt to access element from zero sized row"
+            << "Attempt to access element from empty matrix"
             << abort(FatalError);
     }
     else if (i<0 || i>=nRows_)
     {
         FatalErrorInFunction
-            << "index " << i << " out of range 0 ... " << nRows_-1
+            << "Index " << i << " out of range 0 ... " << nRows_-1
             << abort(FatalError);
     }
     #endif
@@ -96,10 +158,10 @@ template<class Form, class Type>
 inline void Foam::Matrix<Form, Type>::checkj(const label j) const
 {
     #ifdef FULLDEBUG
-    if (!nCols_)
+    if (!nRows_ || !nCols_)
     {
         FatalErrorInFunction
-            << "attempt to access element from zero sized column"
+            << "Attempt to access element from empty matrix"
             << abort(FatalError);
     }
     else if (j<0 || j>=nCols_)
@@ -112,7 +174,33 @@ inline void Foam::Matrix<Form, Type>::checkj(const label j) const
 }
 
 
-// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+template<class Form, class Type>
+inline Foam::label Foam::Matrix<Form, Type>::ConstBlock::m() const
+{
+    return nRows_;
+}
+
+
+template<class Form, class Type>
+inline Foam::label Foam::Matrix<Form, Type>::ConstBlock::n() const
+{
+    return nCols_;
+}
+
+
+template<class Form, class Type>
+inline Foam::label Foam::Matrix<Form, Type>::Block::m() const
+{
+    return nRows_;
+}
+
+
+template<class Form, class Type>
+inline Foam::label Foam::Matrix<Form, Type>::Block::n() const
+{
+    return nCols_;
+}
+
 
 template<class Form, class Type>
 inline const Type* Foam::Matrix<Form, Type>::v() const
@@ -128,6 +216,238 @@ inline Type* Foam::Matrix<Form, Type>::v()
 }
 
 
+template<class Form, class Type>
+inline typename Foam::Matrix<Form, Type>::ConstBlock
+Foam::Matrix<Form, Type>::block
+(
+    const label m,
+    const label n,
+    const label mStart,
+    const label nStart
+) const
+{
+    return ConstBlock
+    (
+        *this,
+        m,
+        n,
+        mStart,
+        nStart
+    );
+}
+
+
+template<class Form, class Type>
+template<class VectorSpace>
+inline typename Foam::Matrix<Form, Type>::ConstBlock
+Foam::Matrix<Form, Type>::block
+(
+    const label mStart,
+    const label nStart
+) const
+{
+    return ConstBlock
+    (
+        *this,
+        VectorSpace::nRows,
+        VectorSpace::nCols,
+        mStart,
+        nStart
+    );
+}
+
+
+template<class Form, class Type>
+inline typename Foam::Matrix<Form, Type>::ConstBlock
+Foam::Matrix<Form, Type>::col
+(
+    const label m,
+    const label mStart
+) const
+{
+    return ConstBlock
+    (
+        *this,
+        m,
+        1,
+        mStart,
+        0
+    );
+}
+
+
+template<class Form, class Type>
+inline typename Foam::Matrix<Form, Type>::ConstBlock
+Foam::Matrix<Form, Type>::col
+(
+    const label m,
+    const label mStart,
+    const label nStart
+) const
+{
+    return ConstBlock
+    (
+        *this,
+        m,
+        1,
+        mStart,
+        nStart
+    );
+}
+
+
+template<class Form, class Type>
+inline typename Foam::Matrix<Form, Type>::Block
+Foam::Matrix<Form, Type>::block
+(
+    const label m,
+    const label n,
+    const label mStart,
+    const label nStart
+)
+{
+    return Block
+    (
+        *this,
+        m,
+        n,
+        mStart,
+        nStart
+    );
+}
+
+
+template<class Form, class Type>
+template<class VectorSpace>
+inline typename Foam::Matrix<Form, Type>::Block
+Foam::Matrix<Form, Type>::block(const label mStart, const label nStart)
+{
+    return Block
+    (
+        *this,
+        VectorSpace::nRows,
+        VectorSpace::nCols,
+        mStart,
+        nStart
+    );
+}
+
+
+template<class Form, class Type>
+inline typename Foam::Matrix<Form, Type>::Block
+Foam::Matrix<Form, Type>::col(const label m, const label mStart)
+{
+    return Block
+    (
+        *this,
+        m,
+        1,
+        mStart,
+        0
+    );
+}
+
+
+template<class Form, class Type>
+inline typename Foam::Matrix<Form, Type>::Block
+Foam::Matrix<Form, Type>::col
+(
+    const label m,
+    const label mStart,
+    const label nStart
+)
+{
+    return Block
+    (
+        *this,
+        m,
+        1,
+        mStart,
+        nStart
+    );
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+template<class Form, class Type>
+inline const Type& Foam::Matrix<Form, Type>::ConstBlock::operator()
+(
+    const label i,
+    const label j
+) const
+{
+    #ifdef FULLDEBUG
+    if (i<0 || i>=nRows_)
+    {
+        FatalErrorInFunction
+            << "Index " << i << " out of range 0 ... " << nRows_-1
+            << abort(FatalError);
+    }
+    if (j<0 || j>=nCols_)
+    {
+        FatalErrorInFunction
+            << "Index " << j << " out of range 0 ... " << nCols_-1
+            << abort(FatalError);
+    }
+    #endif
+
+    return matrix_(i + rowStart_, j + colStart_);
+}
+
+
+template<class Form, class Type>
+inline const Type& Foam::Matrix<Form, Type>::Block::operator()
+(
+    const label i,
+    const label j
+) const
+{
+    #ifdef FULLDEBUG
+    if (i<0 || i>=nRows_)
+    {
+        FatalErrorInFunction
+            << "Index " << i << " out of range 0 ... " << nRows_-1
+            << abort(FatalError);
+    }
+    if (j<0 || j>=nCols_)
+    {
+        FatalErrorInFunction
+            << "Index " << j << " out of range 0 ... " << nCols_-1
+            << abort(FatalError);
+    }
+    #endif
+
+    return matrix_(i + rowStart_, j + colStart_);
+}
+
+
+template<class Form, class Type>
+inline Type& Foam::Matrix<Form, Type>::Block::operator()
+(
+    const label i,
+    const label j
+)
+{
+    #ifdef FULLDEBUG
+    if (i<0 || i>=nRows_)
+    {
+        FatalErrorInFunction
+            << "Index " << i << " out of range 0 ... " << nRows_-1
+            << abort(FatalError);
+    }
+    if (j<0 || j>=nCols_)
+    {
+        FatalErrorInFunction
+            << "Index " << j << " out of range 0 ... " << nCols_-1
+            << abort(FatalError);
+    }
+    #endif
+
+    return matrix_(i + rowStart_, j + colStart_);
+}
+
+
 template<class Form, class Type>
 inline const Type& Foam::Matrix<Form, Type>::operator()
 (
-- 
GitLab