From 878866b16e432faa3febb0bfd0f3f82534b51d39 Mon Sep 17 00:00:00 2001
From: Henry Weller <http://cfd.direct>
Date: Wed, 23 Mar 2016 12:50:34 +0000
Subject: [PATCH] MatrixBlock: Separate Matrix::Block into the separate class
 MatrixBlock

This avoids serious problems with template parameter deduction when
manipulating blocks of different matrix types e.g. Square and
Rectangular.
---
 src/OpenFOAM/matrices/Matrix/Matrix.C         | 562 +++++++-----------
 src/OpenFOAM/matrices/Matrix/Matrix.H         | 214 ++-----
 src/OpenFOAM/matrices/Matrix/MatrixI.H        | 220 +------
 src/OpenFOAM/matrices/Matrix/MatrixIO.C       |   8 +-
 .../matrices/MatrixBlock/MatrixBlock.C        | 342 +++++++++++
 .../matrices/MatrixBlock/MatrixBlock.H        | 240 ++++++++
 .../matrices/MatrixBlock/MatrixBlockI.H       | 203 +++++++
 7 files changed, 1060 insertions(+), 729 deletions(-)
 create mode 100644 src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.C
 create mode 100644 src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.H
 create mode 100644 src/OpenFOAM/matrices/MatrixBlock/MatrixBlockI.H

diff --git a/src/OpenFOAM/matrices/Matrix/Matrix.C b/src/OpenFOAM/matrices/Matrix/Matrix.C
index 808e00b86c2..46508d8e3f6 100644
--- a/src/OpenFOAM/matrices/Matrix/Matrix.C
+++ b/src/OpenFOAM/matrices/Matrix/Matrix.C
@@ -30,7 +30,7 @@ License
 template<class Form, class Type>
 void Foam::Matrix<Form, Type>::allocate()
 {
-    if (nRows_ && nCols_)
+    if (mRows_ && nCols_)
     {
         v_ = new Type[size()];
     }
@@ -42,14 +42,14 @@ void Foam::Matrix<Form, Type>::allocate()
 template<class Form, class Type>
 Foam::Matrix<Form, Type>::Matrix(const label m, const label n)
 :
-    nRows_(m),
+    mRows_(m),
     nCols_(n),
     v_(NULL)
 {
-    if (nRows_ < 0 || nCols_ < 0)
+    if (mRows_ < 0 || nCols_ < 0)
     {
         FatalErrorInFunction
-            << "Bad m, n " << nRows_ << ", " << nCols_
+            << "Incorrect m, n " << mRows_ << ", " << nCols_
             << abort(FatalError);
     }
 
@@ -60,14 +60,14 @@ Foam::Matrix<Form, Type>::Matrix(const label m, const label n)
 template<class Form, class Type>
 Foam::Matrix<Form, Type>::Matrix(const label m, const label n, const zero)
 :
-    nRows_(m),
+    mRows_(m),
     nCols_(n),
     v_(NULL)
 {
-    if (nRows_ < 0 || nCols_ < 0)
+    if (mRows_ < 0 || nCols_ < 0)
     {
         FatalErrorInFunction
-            << "Bad m, n " << nRows_ << ", " << nCols_
+            << "Incorrect m, n " << mRows_ << ", " << nCols_
             << abort(FatalError);
     }
 
@@ -85,16 +85,16 @@ Foam::Matrix<Form, Type>::Matrix(const label m, const label n, const zero)
 
 
 template<class Form, class Type>
-Foam::Matrix<Form, Type>::Matrix(const label m, const label n, const Type& a)
+Foam::Matrix<Form, Type>::Matrix(const label m, const label n, const Type& s)
 :
-    nRows_(m),
+    mRows_(m),
     nCols_(n),
     v_(NULL)
 {
-    if (nRows_ < 0 || nCols_ < 0)
+    if (mRows_ < 0 || nCols_ < 0)
     {
         FatalErrorInFunction
-            << "Bad m, n " << nRows_ << ", " << nCols_
+            << "Incorrect m, n " << mRows_ << ", " << nCols_
             << abort(FatalError);
     }
 
@@ -105,45 +105,92 @@ Foam::Matrix<Form, Type>::Matrix(const label m, const label n, const Type& a)
         const label mn = size();
         for (label i=0; i<mn; i++)
         {
-            v_[i] = a;
+            v_[i] = s;
         }
     }
 }
 
 
 template<class Form, class Type>
-inline Foam::Matrix<Form, Type>::Matrix(const mType::Block& block)
+Foam::Matrix<Form, Type>::Matrix(const Matrix<Form, Type>& M)
 :
-    nRows_(block.m()),
-    nCols_(block.n())
+    mRows_(M.mRows_),
+    nCols_(M.nCols_),
+    v_(NULL)
 {
-    allocate();
-
-    for (label i=0; i<nRows_; i++)
+    if (M.v_)
     {
-        for (label j=0; j<nCols_; j++)
+        allocate();
+
+        const label mn = size();
+        for (label i=0; i<mn; i++)
         {
-            (*this)(i,j) = block(i,j);
+            v_[i] = M.v_[i];
         }
     }
 }
 
 
 template<class Form, class Type>
-Foam::Matrix<Form, Type>::Matrix(const Matrix<Form, Type>& a)
+template<class Form2>
+Foam::Matrix<Form, Type>::Matrix(const Matrix<Form2, Type>& M)
 :
-    nRows_(a.nRows_),
-    nCols_(a.nCols_),
+    mRows_(M.m()),
+    nCols_(M.n()),
     v_(NULL)
 {
-    if (a.v_)
+    if (M.v())
     {
         allocate();
 
         const label mn = size();
         for (label i=0; i<mn; i++)
         {
-            v_[i] = a.v_[i];
+            v_[i] = M.v()[i];
+        }
+    }
+}
+
+
+template<class Form, class Type>
+template<class MatrixType>
+inline Foam::Matrix<Form, Type>::Matrix
+(
+    const ConstMatrixBlock<MatrixType>& Mb
+)
+:
+    mRows_(Mb.m()),
+    nCols_(Mb.n())
+{
+    allocate();
+
+    for (label i=0; i<mRows_; i++)
+    {
+        for (label j=0; j<nCols_; j++)
+        {
+            (*this)(i,j) = Mb(i,j);
+        }
+    }
+}
+
+
+template<class Form, class Type>
+template<class MatrixType>
+inline Foam::Matrix<Form, Type>::Matrix
+(
+    const MatrixBlock<MatrixType>& Mb
+)
+:
+    mRows_(Mb.m()),
+    nCols_(Mb.n())
+{
+    allocate();
+
+    for (label i=0; i<mRows_; i++)
+    {
+        for (label j=0; j<nCols_; j++)
+        {
+            (*this)(i,j) = Mb(i,j);
         }
     }
 }
@@ -172,24 +219,24 @@ void Foam::Matrix<Form, Type>::clear()
         v_ = NULL;
     }
 
-    nRows_ = 0;
+    mRows_ = 0;
     nCols_ = 0;
 }
 
 
 template<class Form, class Type>
-void Foam::Matrix<Form, Type>::transfer(Matrix<Form, Type>& a)
+void Foam::Matrix<Form, Type>::transfer(Matrix<Form, Type>& M)
 {
     clear();
 
-    nRows_ = a.nRows_;
-    a.nRows_ = 0;
+    mRows_ = M.mRows_;
+    M.mRows_ = 0;
 
-    nCols_ = a.nCols_;
-    a.nCols_ = 0;
+    nCols_ = M.nCols_;
+    M.nCols_ = 0;
 
-    v_ = a.v_;
-    a.v_ = NULL;
+    v_ = M.v_;
+    M.v_ = NULL;
 }
 
 
@@ -198,7 +245,7 @@ void Foam::Matrix<Form, Type>::setSize(const label m, const label n)
 {
     mType newMatrix(m, n, Zero);
 
-    label minM = min(m, nRows_);
+    label minM = min(m, mRows_);
     label minN = min(n, nCols_);
 
     for (label i=0; i<minM; i++)
@@ -231,65 +278,23 @@ Form Foam::Matrix<Form, Type>::T() const
 }
 
 
-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>
-Foam::Matrix<Form, Type>::Block::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;
-}
-
-
 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
 template<class Form, class Type>
-void Foam::Matrix<Form, Type>::operator=(const Matrix<Form, Type>& a)
+void Foam::Matrix<Form, Type>::operator=(const Matrix<Form, Type>& M)
 {
-    if (this == &a)
+    if (this == &M)
     {
         FatalErrorInFunction
             << "Attempted assignment to self"
             << abort(FatalError);
     }
 
-    if (nRows_ != a.nRows_ || nCols_ != a.nCols_)
+    if (mRows_ != M.mRows_ || nCols_ != M.nCols_)
     {
         clear();
-        nRows_ = a.nRows_;
-        nCols_ = a.nCols_;
+        mRows_ = M.mRows_;
+        nCols_ = M.nCols_;
         allocate();
     }
 
@@ -298,106 +303,55 @@ void Foam::Matrix<Form, Type>::operator=(const Matrix<Form, Type>& a)
         const label mn = size();
         for (label i=0; i<mn; i++)
         {
-            v_[i] = a.v_[i];
+            v_[i] = M.v_[i];
         }
     }
 }
 
 
 template<class Form, class Type>
-void Foam::Matrix<Form, Type>::operator=(const mType::Block& block)
+template<class MatrixType>
+void Foam::Matrix<Form, Type>::operator=
+(
+    const ConstMatrixBlock<MatrixType>& Mb
+)
 {
-    for (label i=0; i<nRows_; i++)
+    for (label i=0; i<mRows_; i++)
     {
         for (label j=0; j<nCols_; j++)
         {
-            (*this)(i,j) = block(i,j);
+            (*this)(i,j) = Mb(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)
+template<class MatrixType>
+void Foam::Matrix<Form, Type>::operator=
+(
+    const MatrixBlock<MatrixType>& Mb
+)
 {
-    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 i=0; i<mRows_; i++)
     {
         for (label j=0; j<nCols_; j++)
         {
-            (*this)(i, j) = block(i, j);
+            (*this)(i,j) = Mb(i,j);
         }
     }
 }
 
 
 template<class Form, class Type>
-void Foam::Matrix<Form, Type>::operator=(const Type& t)
+void Foam::Matrix<Form, Type>::operator=(const Type& s)
 {
     if (v_)
     {
         const label mn = size();
         for (label i=0; i<mn; i++)
         {
-            v_[i] = t;
+            v_[i] = s;
         }
     }
 }
@@ -417,155 +371,27 @@ void Foam::Matrix<Form, Type>::operator=(const 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>
-const Type& Foam::max(const Matrix<Form, Type>& a)
+const Type& Foam::max(const Matrix<Form, Type>& M)
 {
-    const label mn = a.size();
+    const label mn = M.size();
 
     if (mn)
     {
         label curMaxI = 0;
-        const Type* v = a.v();
+        const Type* Mv = M.v();
 
         for (label i=1; i<mn; i++)
         {
-            if (v[i] > v[curMaxI])
+            if (Mv[i] > Mv[curMaxI])
             {
                 curMaxI = i;
             }
         }
 
-        return v[curMaxI];
+        return Mv[curMaxI];
     }
     else
     {
@@ -574,30 +400,30 @@ const Type& Foam::max(const Matrix<Form, Type>& a)
             << abort(FatalError);
 
         // Return in error to keep compiler happy
-        return a(0, 0);
+        return M(0, 0);
     }
 }
 
 
 template<class Form, class Type>
-const Type& Foam::min(const Matrix<Form, Type>& a)
+const Type& Foam::min(const Matrix<Form, Type>& M)
 {
-    const label mn = a.size();
+    const label mn = M.size();
 
     if (mn)
     {
         label curMinI = 0;
-        const Type* v = a.v();
+        const Type* Mv = M.v();
 
         for (label i=1; i<mn; i++)
         {
-            if (v[i] < v[curMinI])
+            if (Mv[i] < Mv[curMinI])
             {
                 curMinI = i;
             }
         }
 
-        return v[curMinI];
+        return Mv[curMinI];
     }
     else
     {
@@ -606,7 +432,7 @@ const Type& Foam::min(const Matrix<Form, Type>& a)
             << abort(FatalError);
 
         // Return in error to keep compiler happy
-        return a(0, 0);
+        return M(0, 0);
     }
 }
 
@@ -614,187 +440,197 @@ const Type& Foam::min(const Matrix<Form, Type>& a)
 // * * * * * * * * * * * * * * * Global Operators  * * * * * * * * * * * * * //
 
 template<class Form, class Type>
-Form Foam::operator-(const Matrix<Form, Type>& a)
+Form Foam::operator-(const Matrix<Form, Type>& M)
 {
-    Form na(a.m(), a.n());
+    Form nM(M.m(), M.n());
 
-    if (a.m() && a.n())
+    if (M.m() && M.n())
     {
-        Type* nav = na.v();
-        const Type* av = a.v();
+        Type* nMv = nM.v();
+        const Type* Mv = M.v();
 
-        const label mn = a.size();
+        const label mn = M.size();
         for (label i=0; i<mn; i++)
         {
-            nav[i] = -av[i];
+            nMv[i] = -Mv[i];
         }
     }
 
-    return na;
+    return nM;
 }
 
 
 template<class Form, class Type>
-Form Foam::operator+(const Matrix<Form, Type>& a, const Matrix<Form, Type>& b)
+Form Foam::operator+(const Matrix<Form, Type>& A, const Matrix<Form, Type>& B)
 {
-    if (a.m() != b.m())
+    if (A.m() != B.m())
     {
         FatalErrorInFunction
-            << "Attempt to add matrices with different number of rows: "
-            << a.m() << ", " << b.m()
+            << "Attempt to add matrices with different numbers of rows: "
+            << A.m() << ", " << B.m()
             << abort(FatalError);
     }
 
-    if (a.n() != b.n())
+    if (A.n() != B.n())
     {
         FatalErrorInFunction
-            << "Attempt to add matrices with different number of columns: "
-            << a.n() << ", " << b.n()
+            << "Attempt to add matrices with different numbers of columns: "
+            << A.n() << ", " << B.n()
             << abort(FatalError);
     }
 
-    Form ab(a.m(), a.n());
+    Form AB(A.m(), A.n());
 
-    Type* abv = ab.v();
-    const Type* av = a.v();
-    const Type* bv = b.v();
+    Type* ABv = AB.v();
+    const Type* Av = A.v();
+    const Type* Bv = B.v();
 
-    const label mn = a.size();
+    const label mn = A.size();
     for (label i=0; i<mn; i++)
     {
-        abv[i] = av[i] + bv[i];
+        ABv[i] = Av[i] + Bv[i];
     }
 
-    return ab;
+    return AB;
 }
 
 
 template<class Form, class Type>
-Form Foam::operator-(const Matrix<Form, Type>& a, const Matrix<Form, Type>& b)
+Form Foam::operator-(const Matrix<Form, Type>& A, const Matrix<Form, Type>& B)
 {
-    if (a.m() != b.m())
+    if (A.m() != B.m())
     {
         FatalErrorInFunction
-            << "Attempt to add matrices with different number of rows: "
-            << a.m() << ", " << b.m()
+            << "Attempt to add matrices with different numbers of rows: "
+            << A.m() << ", " << B.m()
             << abort(FatalError);
     }
 
-    if (a.n() != b.n())
+    if (A.n() != B.n())
     {
         FatalErrorInFunction
-            << "Attempt to add matrices with different number of columns: "
-            << a.n() << ", " << b.n()
+            << "Attempt to add matrices with different numbers of columns: "
+            << A.n() << ", " << B.n()
             << abort(FatalError);
     }
 
-    Form ab(a.m(), a.n());
+    Form AB(A.m(), A.n());
 
-    Type* abv = ab.v();
-    const Type* av = a.v();
-    const Type* bv = b.v();
+    Type* ABv = AB.v();
+    const Type* Av = A.v();
+    const Type* Bv = B.v();
 
-    const label mn = a.size();
+    const label mn = A.size();
     for (label i=0; i<mn; i++)
     {
-        abv[i] = av[i] - bv[i];
+        ABv[i] = Av[i] - Bv[i];
     }
 
-    return ab;
+    return AB;
 }
 
 
 template<class Form, class Type>
-Form Foam::operator*(const scalar s, const Matrix<Form, Type>& a)
+Form Foam::operator*(const scalar s, const Matrix<Form, Type>& M)
 {
-    Form sa(a.m(), a.n());
+    Form sM(M.m(), M.n());
 
-    if (a.m() && a.n())
+    if (M.m() && M.n())
     {
-        Type* sav = sa.v();
-        const Type* av = a.v();
+        Type* sMv = sM.v();
+        const Type* Mv = M.v();
 
-        const label mn = a.size();
+        const label mn = M.size();
         for (label i=0; i<mn; i++)
         {
-            sav[i] = s*av[i];
+            sMv[i] = s*Mv[i];
         }
     }
 
-    return sa;
+    return sM;
 }
 
 
 template<class Form, class Type>
-Form Foam::operator*(const Matrix<Form, Type>& a, const scalar s)
+Form Foam::operator*(const Matrix<Form, Type>& M, const scalar s)
 {
-    Form sa(a.m(), a.n());
+    Form sM(M.m(), M.n());
 
-    if (a.m() && a.n())
+    if (M.m() && M.n())
     {
-        Type* sav = sa.v();
-        const Type* av = a.v();
+        Type* sMv = sM.v();
+        const Type* Mv = M.v();
 
-        const label mn = a.size();
+        const label mn = M.size();
         for (label i=0; i<mn; i++)
         {
-            sav[i] = av[i]*s;
+            sMv[i] = Mv[i]*s;
         }
     }
 
-    return sa;
+    return sM;
 }
 
 
 template<class Form, class Type>
-Form Foam::operator/(const Matrix<Form, Type>& a, const scalar s)
+Form Foam::operator/(const Matrix<Form, Type>& M, const scalar s)
 {
-    Form sa(a.m(), a.n());
+    Form sM(M.m(), M.n());
 
-    if (a.m() && a.n())
+    if (M.m() && M.n())
     {
-        Type* sav = sa.v();
-        const Type* av = a.v();
+        Type* sMv = sM.v();
+        const Type* Mv = M.v();
 
-        const label mn = a.size();
+        const label mn = M.size();
         for (label i=0; i<mn; i++)
         {
-            sav[i] = av[i]/s;
+            sMv[i] = Mv[i]/s;
         }
     }
 
-    return sa;
+    return sM;
 }
 
 
-template<class Form, class Type>
-Form Foam::operator*(const Matrix<Form, Type>& a, const Matrix<Form, Type>& b)
+template<class Form1, class Form2, class Type>
+typename Foam::typeOfInnerProduct<Type, Form1, Form2>::type
+Foam::operator*
+(
+    const Matrix<Form1, Type>& A,
+    const Matrix<Form2, Type>& B
+)
 {
-    if (a.n() != b.m())
+    if (A.n() != B.m())
     {
         FatalErrorInFunction
             << "Attempt to multiply incompatible matrices:" << nl
-            << "Matrix A : " << a.m() << " rows, " << a.n() << " columns" << nl
-            << "Matrix B : " << b.m() << " rows, " << b.n() << " columns" << nl
+            << "Matrix A : " << A.m() << " x " << A.n() << nl
+            << "Matrix B : " << B.m() << " x " << B.n() << nl
             << "In order to multiply matrices, columns of A must equal "
             << "rows of B"
             << abort(FatalError);
     }
 
-    Form ab(a.m(), b.n(), scalar(0));
+    typename typeOfInnerProduct<Type, Form1, Form2>::type AB
+    (
+        A.m(),
+        B.n(),
+        Zero
+    );
 
-    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 k=0; k<b.m(); k++)
+            for (label k=0; k<B.m(); k++)
             {
-                ab(i, j) += a(i, k)*b(k, j);
+                AB(i, j) += A(i, k)*B(k, j);
             }
         }
     }
 
-    return ab;
+    return AB;
 }
 
 
@@ -809,7 +645,7 @@ inline Foam::tmp<Foam::Field<Type>> Foam::operator*
     {
         FatalErrorInFunction
             << "Attempt to multiply incompatible matrix and field:" << nl
-            << "Matrix : " << M.m() << " rows, " << M.n() << " columns" << nl
+            << "Matrix : " << M.m() << " x " << M.n() << nl
             << "Field : " << f.size() << " rows" << nl
             << "In order to multiply a matrix M and field f, "
                "columns of M must equal rows of f"
@@ -819,9 +655,9 @@ inline Foam::tmp<Foam::Field<Type>> Foam::operator*
     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 i=0; i<M.m(); i++)
     {
-        for (label j=0; j<M.n(); ++j)
+        for (label j=0; j<M.n(); j++)
         {
             Mf[i] += M(i, j)*f[j];
         }
diff --git a/src/OpenFOAM/matrices/Matrix/Matrix.H b/src/OpenFOAM/matrices/Matrix/Matrix.H
index 5f905b465bc..9385d42d873 100644
--- a/src/OpenFOAM/matrices/Matrix/Matrix.H
+++ b/src/OpenFOAM/matrices/Matrix/Matrix.H
@@ -25,8 +25,7 @@ Class
     Foam::Matrix
 
 Description
-    A templated 2D matrix of objects of \<T\>, where the n x m matrix
-    dimensions are known and used for subscript bounds checking, etc.
+    A templated (m x n) matrix of objects of \<T\>.
 
 SourceFiles
     Matrix.C
@@ -42,7 +41,6 @@ SourceFiles
 #include "label.H"
 #include "uLabel.H"
 #include "Field.H"
-#include "MatrixSpace.H"
 #include "zero.H"
 #include "autoPtr.H"
 
@@ -67,6 +65,12 @@ template<class Form, class Type> Ostream& operator<<
     const Matrix<Form, Type>&
 );
 
+template<class MatrixType>
+class ConstMatrixBlock;
+
+template<class MatrixType>
+class MatrixBlock;
+
 
 /*---------------------------------------------------------------------------*\
                            Class Matrix Declaration
@@ -78,7 +82,7 @@ class Matrix
     // Private data
 
         //- Number of rows and columns in Matrix.
-        label nRows_, nCols_;
+        label mRows_, nCols_;
 
         //- Row pointers
         Type* __restrict__ v_;
@@ -102,157 +106,6 @@ public:
         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
 
         //- Null constructor.
@@ -272,8 +125,17 @@ public:
         //- Copy constructor.
         Matrix(const mType&);
 
+        //- Copy constructor from matrix of a different form
+        template<class Form2>
+        explicit Matrix(const Matrix<Form2, Type>&);
+
+        //- Construct from a block of another matrix
+        template<class MatrixType>
+        Matrix(const ConstMatrixBlock<MatrixType>&);
+
         //- Construct from a block of another matrix
-        Matrix(const mType::Block&);
+        template<class MatrixType>
+        Matrix(const MatrixBlock<MatrixType>&);
 
         //- Construct from Istream.
         Matrix(Istream&);
@@ -308,7 +170,7 @@ public:
 
         // Block access
 
-            inline ConstBlock block
+            inline ConstMatrixBlock<mType> block
             (
                 const label m,
                 const label n,
@@ -317,19 +179,19 @@ public:
             ) const;
 
             template<class VectorSpace>
-            inline ConstBlock block
+            inline ConstMatrixBlock<mType> block
             (
                 const label mStart,
                 const label nStart
             ) const;
 
-            inline ConstBlock col
+            inline ConstMatrixBlock<mType> col
             (
                 const label m,
                 const label rowStart
             ) const;
 
-            inline ConstBlock col
+            inline ConstMatrixBlock<mType> col
             (
                 const label m,
                 const label mStart,
@@ -337,7 +199,7 @@ public:
             ) const;
 
 
-            inline Block block
+            inline MatrixBlock<mType> block
             (
                 const label m,
                 const label n,
@@ -346,11 +208,19 @@ public:
             );
 
             template<class VectorSpace>
-            inline Block block(const label mStart, const label nStart);
+            inline MatrixBlock<mType> block
+            (
+                const label mStart,
+                const label nStart
+            );
 
-            inline Block col(const label m, const label rowStart);
+            inline MatrixBlock<mType> col
+            (
+                const label m,
+                const label rowStart
+            );
 
-            inline Block col
+            inline MatrixBlock<mType> col
             (
                 const label m,
                 const label mStart,
@@ -402,7 +272,12 @@ public:
         void operator=(const mType&);
 
         //- Assignment to a block of another matrix
-        void operator=(const mType::Block&);
+        template<class MatrixType>
+        void operator=(const ConstMatrixBlock<MatrixType>&);
+
+        //- Assignment to a block of another matrix
+        template<class MatrixType>
+        void operator=(const MatrixBlock<MatrixType>&);
 
         //- Assignment of all entries to zero
         void operator=(const zero);
@@ -475,11 +350,12 @@ Form operator/
     const scalar
 );
 
-template<class Form, class Type>
-Form operator*
+template<class Form1, class Form2, class Type>
+typename typeOfInnerProduct<Type, Form1, Form2>::type
+operator*
 (
-    const Matrix<Form, Type>&,
-    const Matrix<Form, Type>&
+    const Matrix<Form1, Type>& a,
+    const Matrix<Form2, Type>& b
 );
 
 template<class Form, class Type>
diff --git a/src/OpenFOAM/matrices/Matrix/MatrixI.H b/src/OpenFOAM/matrices/Matrix/MatrixI.H
index 73992f3285d..73992aac77b 100644
--- a/src/OpenFOAM/matrices/Matrix/MatrixI.H
+++ b/src/OpenFOAM/matrices/Matrix/MatrixI.H
@@ -23,12 +23,14 @@ License
 
 \*---------------------------------------------------------------------------*/
 
+#include "MatrixBlock.H"
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 template<class Form, class Type>
 inline Foam::Matrix<Form, Type>::Matrix()
 :
-    nRows_(0),
+    mRows_(0),
     nCols_(0),
     v_(NULL)
 {}
@@ -42,68 +44,6 @@ 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>
@@ -116,7 +56,7 @@ inline const Foam::Matrix<Form, Type>& Foam::Matrix<Form, Type>::null()
 template<class Form, class Type>
 inline Foam::label Foam::Matrix<Form, Type>::m() const
 {
-    return nRows_;
+    return mRows_;
 }
 
 
@@ -130,7 +70,7 @@ inline Foam::label Foam::Matrix<Form, Type>::n() const
 template<class Form, class Type>
 inline Foam::label Foam::Matrix<Form, Type>::size() const
 {
-    return nRows_*nCols_;
+    return mRows_*nCols_;
 }
 
 
@@ -138,16 +78,16 @@ template<class Form, class Type>
 inline void Foam::Matrix<Form, Type>::checki(const label i) const
 {
     #ifdef FULLDEBUG
-    if (!nRows_ || !nCols_)
+    if (!mRows_ || !nCols_)
     {
         FatalErrorInFunction
             << "Attempt to access element from empty matrix"
             << abort(FatalError);
     }
-    else if (i<0 || i>=nRows_)
+    else if (i<0 || i>=mRows_)
     {
         FatalErrorInFunction
-            << "Index " << i << " out of range 0 ... " << nRows_-1
+            << "Index " << i << " out of range 0 ... " << mRows_-1
             << abort(FatalError);
     }
     #endif
@@ -158,7 +98,7 @@ template<class Form, class Type>
 inline void Foam::Matrix<Form, Type>::checkj(const label j) const
 {
     #ifdef FULLDEBUG
-    if (!nRows_ || !nCols_)
+    if (!mRows_ || !nCols_)
     {
         FatalErrorInFunction
             << "Attempt to access element from empty matrix"
@@ -174,34 +114,6 @@ inline void Foam::Matrix<Form, Type>::checkj(const label j) const
 }
 
 
-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
 {
@@ -217,7 +129,7 @@ inline Type* Foam::Matrix<Form, Type>::v()
 
 
 template<class Form, class Type>
-inline typename Foam::Matrix<Form, Type>::ConstBlock
+inline Foam::ConstMatrixBlock<Foam::Matrix<Form, Type>>
 Foam::Matrix<Form, Type>::block
 (
     const label m,
@@ -226,7 +138,7 @@ Foam::Matrix<Form, Type>::block
     const label nStart
 ) const
 {
-    return ConstBlock
+    return ConstMatrixBlock<mType>
     (
         *this,
         m,
@@ -239,17 +151,17 @@ Foam::Matrix<Form, Type>::block
 
 template<class Form, class Type>
 template<class VectorSpace>
-inline typename Foam::Matrix<Form, Type>::ConstBlock
+inline Foam::ConstMatrixBlock<Foam::Matrix<Form, Type>>
 Foam::Matrix<Form, Type>::block
 (
     const label mStart,
     const label nStart
 ) const
 {
-    return ConstBlock
+    return ConstMatrixBlock<mType>
     (
         *this,
-        VectorSpace::nRows,
+        VectorSpace::mRows,
         VectorSpace::nCols,
         mStart,
         nStart
@@ -258,14 +170,14 @@ Foam::Matrix<Form, Type>::block
 
 
 template<class Form, class Type>
-inline typename Foam::Matrix<Form, Type>::ConstBlock
+inline Foam::ConstMatrixBlock<Foam::Matrix<Form, Type>>
 Foam::Matrix<Form, Type>::col
 (
     const label m,
     const label mStart
 ) const
 {
-    return ConstBlock
+    return ConstMatrixBlock<mType>
     (
         *this,
         m,
@@ -277,7 +189,7 @@ Foam::Matrix<Form, Type>::col
 
 
 template<class Form, class Type>
-inline typename Foam::Matrix<Form, Type>::ConstBlock
+inline Foam::ConstMatrixBlock<Foam::Matrix<Form, Type>>
 Foam::Matrix<Form, Type>::col
 (
     const label m,
@@ -285,7 +197,7 @@ Foam::Matrix<Form, Type>::col
     const label nStart
 ) const
 {
-    return ConstBlock
+    return ConstMatrixBlock<mType>
     (
         *this,
         m,
@@ -297,7 +209,7 @@ Foam::Matrix<Form, Type>::col
 
 
 template<class Form, class Type>
-inline typename Foam::Matrix<Form, Type>::Block
+inline Foam::MatrixBlock<Foam::Matrix<Form, Type>>
 Foam::Matrix<Form, Type>::block
 (
     const label m,
@@ -306,7 +218,7 @@ Foam::Matrix<Form, Type>::block
     const label nStart
 )
 {
-    return Block
+    return MatrixBlock<mType>
     (
         *this,
         m,
@@ -319,13 +231,13 @@ Foam::Matrix<Form, Type>::block
 
 template<class Form, class Type>
 template<class VectorSpace>
-inline typename Foam::Matrix<Form, Type>::Block
+inline Foam::MatrixBlock<Foam::Matrix<Form, Type>>
 Foam::Matrix<Form, Type>::block(const label mStart, const label nStart)
 {
-    return Block
+    return MatrixBlock<mType>
     (
         *this,
-        VectorSpace::nRows,
+        VectorSpace::mRows,
         VectorSpace::nCols,
         mStart,
         nStart
@@ -334,10 +246,10 @@ Foam::Matrix<Form, Type>::block(const label mStart, const label nStart)
 
 
 template<class Form, class Type>
-inline typename Foam::Matrix<Form, Type>::Block
+inline Foam::MatrixBlock<Foam::Matrix<Form, Type>>
 Foam::Matrix<Form, Type>::col(const label m, const label mStart)
 {
-    return Block
+    return MatrixBlock<mType>
     (
         *this,
         m,
@@ -349,7 +261,7 @@ Foam::Matrix<Form, Type>::col(const label m, const label mStart)
 
 
 template<class Form, class Type>
-inline typename Foam::Matrix<Form, Type>::Block
+inline Foam::MatrixBlock<Foam::Matrix<Form, Type>>
 Foam::Matrix<Form, Type>::col
 (
     const label m,
@@ -357,7 +269,7 @@ Foam::Matrix<Form, Type>::col
     const label nStart
 )
 {
-    return Block
+    return MatrixBlock<mType>
     (
         *this,
         m,
@@ -370,84 +282,6 @@ Foam::Matrix<Form, Type>::col
 
 // * * * * * * * * * * * * * * * 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()
 (
diff --git a/src/OpenFOAM/matrices/Matrix/MatrixIO.C b/src/OpenFOAM/matrices/Matrix/MatrixIO.C
index 9be178c12f3..51943ada59f 100644
--- a/src/OpenFOAM/matrices/Matrix/MatrixIO.C
+++ b/src/OpenFOAM/matrices/Matrix/MatrixIO.C
@@ -34,7 +34,7 @@ License
 template<class Form, class Type>
 Foam::Matrix<Form, Type>::Matrix(Istream& is)
 :
-    nRows_(0),
+    mRows_(0),
     nCols_(0),
     v_(NULL)
 {
@@ -59,10 +59,10 @@ Foam::Istream& Foam::operator>>(Istream& is, Matrix<Form, Type>& M)
 
     if (firstToken.isLabel())
     {
-        M.nRows_ = firstToken.labelToken();
+        M.mRows_ = firstToken.labelToken();
         M.nCols_ = readLabel(is);
 
-        label mn = M.nRows_*M.nCols_;
+        label mn = M.mRows_*M.nCols_;
 
         // Read list contents depending on data format
         if (is.format() == IOstream::ASCII || !contiguous<Type>())
@@ -151,7 +151,7 @@ Foam::Istream& Foam::operator>>(Istream& is, Matrix<Form, Type>& M)
 template<class Form, class Type>
 Foam::Ostream& Foam::operator<<(Ostream& os, const Matrix<Form, Type>& M)
 {
-    label mn = M.nRows_*M.nCols_;
+    label mn = M.mRows_*M.nCols_;
 
     os  << M.m() << token::SPACE << M.n();
 
diff --git a/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.C b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.C
new file mode 100644
index 00000000000..3aecbe8377d
--- /dev/null
+++ b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.C
@@ -0,0 +1,342 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "MatrixBlock.H"
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class MatrixType>
+Foam::ConstMatrixBlock<MatrixType>::operator Field<cmptType>() const
+{
+    if (nCols_ != 1)
+    {
+        FatalErrorInFunction
+            << "Number of columns " << nCols_ << " != 1"
+            << abort(FatalError);
+    }
+
+    Field<cmptType> f(mRows_);
+
+    forAll(f, i)
+    {
+        f[i] = operator()(i, 0);
+    }
+
+    return f;
+}
+
+
+template<class MatrixType>
+Foam::MatrixBlock<MatrixType>::operator Field<cmptType>() const
+{
+    if (nCols_ != 1)
+    {
+        FatalErrorInFunction
+            << "Number of columns " << nCols_ << " != 1"
+            << abort(FatalError);
+    }
+
+    Field<cmptType> f(mRows_);
+
+    forAll(f, i)
+    {
+        f[i] = operator()(i, 0);
+    }
+
+    return f;
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+template<class MatrixType>
+template<class Form>
+void Foam::MatrixBlock<MatrixType>::operator=
+(
+    const Matrix<Form, cmptType>& Mb
+)
+{
+    if (mRows_ != Mb.m() || nCols_ != Mb.n())
+    {
+        FatalErrorInFunction
+            << "Attempt to assign blocks of different sizes: "
+            << mRows_ << "x" << nCols_ << " != "
+            << Mb.m() << "x" << Mb.n()
+            << abort(FatalError);
+    }
+
+    for (label i=0; i<mRows_; i++)
+    {
+        for (label j=0; j<nCols_; j++)
+        {
+            (*this)(i, j) = Mb(i, j);
+        }
+    }
+}
+
+
+template<class MatrixType>
+void Foam::MatrixBlock<MatrixType>::operator=
+(
+    const ConstMatrixBlock<MatrixType>& Mb
+)
+{
+    if (this != &Mb)
+    {
+        if (mRows_ != Mb.m() || nCols_ != Mb.n())
+        {
+            FatalErrorInFunction
+                << "Attempt to assign blocks of different sizes: "
+                << mRows_ << "x" << nCols_ << " != "
+                << Mb.m() << "x" << Mb.n()
+                << abort(FatalError);
+        }
+
+        for (label i=0; i<mRows_; i++)
+        {
+            for (label j=0; j<nCols_; j++)
+            {
+                (*this)(i, j) = Mb(i, j);
+            }
+        }
+    }
+}
+
+
+template<class MatrixType>
+void Foam::MatrixBlock<MatrixType>::operator=
+(
+    const MatrixBlock<MatrixType>& Mb
+)
+{
+    if (this != &Mb)
+    {
+        if (mRows_ != Mb.m() || nCols_ != Mb.n())
+        {
+            FatalErrorInFunction
+                << "Attempt to assign blocks of different sizes: "
+                << mRows_ << "x" << nCols_ << " != "
+                << Mb.m() << "x" << Mb.n()
+                << abort(FatalError);
+        }
+
+        for (label i=0; i<mRows_; i++)
+        {
+            for (label j=0; j<nCols_; j++)
+            {
+                (*this)(i, j) = Mb(i, j);
+            }
+        }
+    }
+}
+
+
+template<class MatrixType>
+template<class MatrixType2>
+void Foam::MatrixBlock<MatrixType>::operator=
+(
+    const ConstMatrixBlock<MatrixType2>& Mb
+)
+{
+    if (this != &Mb)
+    {
+        if (mRows_ != Mb.m() || nCols_ != Mb.n())
+        {
+            FatalErrorInFunction
+                << "Attempt to assign blocks of different sizes: "
+                << mRows_ << "x" << nCols_ << " != "
+                << Mb.m() << "x" << Mb.n()
+                << abort(FatalError);
+        }
+
+        for (label i=0; i<mRows_; i++)
+        {
+            for (label j=0; j<nCols_; j++)
+            {
+                (*this)(i, j) = Mb(i, j);
+            }
+        }
+    }
+}
+
+
+template<class MatrixType>
+template<class MatrixType2>
+void Foam::MatrixBlock<MatrixType>::operator=
+(
+    const MatrixBlock<MatrixType2>& Mb
+)
+{
+    if (this != &Mb)
+    {
+        if (mRows_ != Mb.m() || nCols_ != Mb.n())
+        {
+            FatalErrorInFunction
+                << "Attempt to assign blocks of different sizes: "
+                << mRows_ << "x" << nCols_ << " != "
+                << Mb.m() << "x" << Mb.n()
+                << abort(FatalError);
+        }
+
+        for (label i=0; i<mRows_; i++)
+        {
+            for (label j=0; j<nCols_; j++)
+            {
+                (*this)(i, j) = Mb(i, j);
+            }
+        }
+    }
+}
+
+
+template<class MatrixType>
+template
+<
+    template<class, Foam::direction, Foam::direction> class MSBlock,
+    class SubTensor,
+    Foam::direction BRowStart,
+    Foam::direction BColStart
+>
+void Foam::MatrixBlock<MatrixType>::operator=
+(
+    const MSBlock<SubTensor, BRowStart, BColStart>& Mb
+)
+{
+    if (mRows_ != Mb.mRows || nCols_ != Mb.nCols)
+    {
+        FatalErrorInFunction
+            << "Attempt to assign blocks of different sizes: "
+            << mRows_ << "x" << nCols_ << " != "
+            << Mb.mRows << "x" << Mb.nCols
+            << abort(FatalError);
+    }
+
+    for (direction i=0; i<mRows_; ++i)
+    {
+        for (direction j=0; j<nCols_; ++j)
+        {
+            operator()(i, j) = Mb(i, j);
+        }
+    }
+}
+
+
+template<class MatrixType>
+template
+<
+    template<class, Foam::direction> class VSBlock,
+    class SubVector,
+    Foam::direction BStart
+>
+void Foam::MatrixBlock<MatrixType>::operator=
+(
+    const VSBlock<SubVector, BStart>& Mb
+)
+{
+    if (mRows_ != Mb.nComponents || nCols_ != 1)
+    {
+        FatalErrorInFunction
+            << "Attempt to assign blocks of different sizes: "
+            << mRows_ << "x" << nCols_ << " != "
+            << Mb.nComponents << "x" << 1
+            << abort(FatalError);
+    }
+
+    for (direction i=0; i<mRows_; ++i)
+    {
+        operator()(i, 0) = Mb[i];
+    }
+}
+
+
+template<class MatrixType>
+template<class MSForm, Foam::direction Nrows, Foam::direction Ncols>
+void Foam::MatrixBlock<MatrixType>::operator=
+(
+    const MatrixSpace<MSForm, cmptType, Nrows, Ncols>& ms
+)
+{
+    if (mRows_ != Nrows || nCols_ != Ncols)
+    {
+        FatalErrorInFunction
+            << "Attempt to assign blocks of different sizes: "
+            << mRows_ << "x" << nCols_ << " != "
+            << Nrows << "x" << Ncols
+            << abort(FatalError);
+    }
+
+    for (label i=0; i<mRows_; i++)
+    {
+        for (label j=0; j<nCols_; j++)
+        {
+            (*this)(i, j) = ms(i, j);
+        }
+    }
+}
+
+
+template<class MatrixType>
+template<class VSForm, Foam::direction Ncmpts>
+void Foam::MatrixBlock<MatrixType>::operator=
+(
+    const VectorSpace<VSForm, cmptType, Ncmpts>& ms
+)
+{
+    if (mRows_ != Ncmpts || nCols_ != 1)
+    {
+        FatalErrorInFunction
+            << "Attempt to assign blocks of different sizes: "
+            << mRows_ << "x" << nCols_ << " != "
+            << Ncmpts << "x" << 1
+            << abort(FatalError);
+    }
+
+    for (direction i=0; i<Ncmpts; ++i)
+    {
+        operator()(i, 0) = ms[i];
+    }
+}
+
+
+template<class MatrixType>
+void Foam::MatrixBlock<MatrixType>::operator=(const Field<cmptType>& f)
+{
+    if (mRows_ != f.size() || nCols_ != 1)
+    {
+        FatalErrorInFunction
+            << "Error: cannot assign blocks of different size (left is "
+            << mRows_ << "x" << nCols_ << " != "
+            << f.size() << "x" << 1
+            << abort(FatalError);
+    }
+
+    forAll(f, i)
+    {
+        operator()(i, 0) = f[i];
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.H b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.H
new file mode 100644
index 00000000000..67ece198eed
--- /dev/null
+++ b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.H
@@ -0,0 +1,240 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::MatrixBlock
+
+Description
+    A templated block of an (m x n) matrix of type \<MatrixType\>.
+
+        Foam::ConstMatrixBlock: block of a const matrix
+        Foam::MatrixBlock: block of a non-const matrix
+
+    The block may be assigned to a block of another matrix or to a VectorSpace
+    or MatrixSpace e.g. \c tensor.  Conversion of a column block to a \c
+    Field<T> is also provide.
+
+SourceFiles
+    MatrixBlock.C
+    MatrixBlockI.H
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef MatrixBlock_H
+#define MatrixBlock_H
+
+#include "Matrix.H"
+#include "MatrixSpace.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                         Class ConstMatrixBlock Declaration
+\*---------------------------------------------------------------------------*/
+
+template<class MatrixType>
+class ConstMatrixBlock
+{
+    // Private data
+
+        //- Const reference to the parent matrix
+        const MatrixType& matrix_;
+
+        // Block size
+        const label mRows_;
+        const label nCols_;
+
+        // Block location in parent matrix
+        const label rowStart_;
+        const label colStart_;
+
+public:
+
+    typedef typename MatrixType::cmptType cmptType;
+
+    // Constructors
+
+        //- Construct block for matrix, size and location
+        inline ConstMatrixBlock
+        (
+            const MatrixType& 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 cmptType& operator()
+        (
+            const label i,
+            const label j
+        ) const;
+
+        //- Convert a column of a matrix to a Field
+        operator Field<cmptType>() const;
+};
+
+
+/*---------------------------------------------------------------------------*\
+                          Class MatrixBlock Declaration
+\*---------------------------------------------------------------------------*/
+
+template<class MatrixType>
+class MatrixBlock
+{
+    // Private data
+
+        //- Reference to the parent matrix
+        MatrixType& matrix_;
+
+        // Block size
+        const label mRows_;
+        const label nCols_;
+
+        // Block location in parent matrix
+        const label rowStart_;
+        const label colStart_;
+
+public:
+
+    typedef typename MatrixType::cmptType cmptType;
+
+    // Constructors
+
+        //- Construct block for matrix, size and location
+        inline MatrixBlock
+        (
+            MatrixType& 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 cmptType& operator()
+        (
+            const label i,
+            const label j
+        ) const;
+
+        //- (i, j) element access operator
+        inline cmptType& operator()(const label i, const label j);
+
+        //- Convert a column of a matrix to a Field
+        operator Field<cmptType>() const;
+
+
+    // Member operators
+
+        //- Assignment to a compatible matrix
+        template<class Form>
+        void operator=(const Matrix<Form, cmptType>&);
+
+        //- Assignment to a compatible const block
+        void operator=(const ConstMatrixBlock<MatrixType>&);
+
+        //- Assignment to a compatible block
+        void operator=(const MatrixBlock<MatrixType>&);
+
+        //- Assignment to a compatible const block
+        template<class MatrixType2>
+        void operator=(const ConstMatrixBlock<MatrixType2>&);
+
+        //- Assignment to a compatible block
+        template<class MatrixType2>
+        void operator=(const MatrixBlock<MatrixType2>&);
+
+        //- Assignment to a compatible MatrixSpace
+        template<class MSForm, direction Nrows, direction Ncols>
+        void operator=(const MatrixSpace<MSForm, cmptType, 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, cmptType, 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<cmptType>&);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "MatrixBlockI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "MatrixBlock.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/matrices/MatrixBlock/MatrixBlockI.H b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlockI.H
new file mode 100644
index 00000000000..e764dea0320
--- /dev/null
+++ b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlockI.H
@@ -0,0 +1,203 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2016 OpenFOAM Foundation
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+template<class MatrixType>
+Foam::ConstMatrixBlock<MatrixType>::ConstMatrixBlock
+(
+    const MatrixType& matrix,
+    const label m,
+    const label n,
+    const label mStart,
+    const label nStart
+)
+:
+    matrix_(matrix),
+    mRows_(m),
+    nCols_(n),
+    rowStart_(mStart),
+    colStart_(nStart)
+{
+    #ifdef FULLDEBUG
+    if
+    (
+        rowStart_ + mRows_ > matrix.m()
+     || colStart_ + nCols_ > matrix.n()
+    )
+    {
+        FatalErrorInFunction
+            << "Block addresses outside matrix"
+            << abort(FatalError);
+    }
+    #endif
+}
+
+
+template<class MatrixType>
+Foam::MatrixBlock<MatrixType>::MatrixBlock
+(
+    MatrixType& matrix,
+    const label m,
+    const label n,
+    const label mStart,
+    const label nStart
+)
+:
+    matrix_(matrix),
+    mRows_(m),
+    nCols_(n),
+    rowStart_(mStart),
+    colStart_(nStart)
+{
+    #ifdef FULLDEBUG
+    if
+    (
+        rowStart_ + mRows_ > matrix.m()
+     || colStart_ + nCols_ > matrix.n()
+    )
+    {
+        FatalErrorInFunction
+            << "Block addresses outside matrix"
+            << abort(FatalError);
+    }
+    #endif
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class MatrixType>
+inline Foam::label Foam::ConstMatrixBlock<MatrixType>::m() const
+{
+    return mRows_;
+}
+
+
+template<class MatrixType>
+inline Foam::label Foam::ConstMatrixBlock<MatrixType>::n() const
+{
+    return nCols_;
+}
+
+
+template<class MatrixType>
+inline Foam::label Foam::MatrixBlock<MatrixType>::m() const
+{
+    return mRows_;
+}
+
+
+template<class MatrixType>
+inline Foam::label Foam::MatrixBlock<MatrixType>::n() const
+{
+    return nCols_;
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+template<class MatrixType>
+inline const typename MatrixType::cmptType&
+Foam::ConstMatrixBlock<MatrixType>::operator()
+(
+    const label i,
+    const label j
+) const
+{
+    #ifdef FULLDEBUG
+    if (i<0 || i>=mRows_)
+    {
+        FatalErrorInFunction
+            << "Index " << i << " out of range 0 ... " << mRows_-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 MatrixType>
+inline const typename MatrixType::cmptType&
+Foam::MatrixBlock<MatrixType>::operator()
+(
+    const label i,
+    const label j
+) const
+{
+    #ifdef FULLDEBUG
+    if (i<0 || i>=mRows_)
+    {
+        FatalErrorInFunction
+            << "Index " << i << " out of range 0 ... " << mRows_-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 MatrixType>
+inline typename MatrixType::cmptType&
+Foam::MatrixBlock<MatrixType>::operator()
+(
+    const label i,
+    const label j
+)
+{
+    #ifdef FULLDEBUG
+    if (i<0 || i>=mRows_)
+    {
+        FatalErrorInFunction
+            << "Index " << i << " out of range 0 ... " << mRows_-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_);
+}
+
+
+// ************************************************************************* //
-- 
GitLab