diff --git a/applications/test/TestTools/TestTools.H b/applications/test/TestTools/TestTools.H
new file mode 100644
index 0000000000000000000000000000000000000000..c24cb9fa051f69335395ec93ebe31049c8f81fab
--- /dev/null
+++ b/applications/test/TestTools/TestTools.H
@@ -0,0 +1,305 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+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/>.
+
+Description
+    Various tools for test applications.
+
+\*---------------------------------------------------------------------------*/
+
+using namespace Foam;
+
+#include "Random.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Total number of unit tests
+unsigned nTest_ = 0;
+
+
+// Total number of failed unit tests
+unsigned nFail_ = 0;
+
+
+// Create a non-complex random Matrix.
+template<class MatrixType>
+typename std::enable_if
+<
+    !std::is_same<complex, typename MatrixType::cmptType>:: value,
+    MatrixType
+>::type makeRandomMatrix
+(
+    const labelPair& dims,
+    Random& rndGen
+)
+{
+    MatrixType mat(dims);
+
+    std::generate
+    (
+        mat.begin(),
+        mat.end(),
+        [&]{return rndGen.GaussNormal<scalar>();}
+    );
+
+    return mat;
+}
+
+
+// Create a complex random Matrix.
+template<class MatrixType>
+typename std::enable_if
+<
+    std::is_same<complex, typename MatrixType::cmptType>:: value,
+    MatrixType
+>::type makeRandomMatrix
+(
+    const labelPair& dims,
+    Random& rndGen
+)
+{
+    MatrixType mat(dims);
+
+    for (auto& x : mat)
+    {
+        x = complex(rndGen.GaussNormal<scalar>(), rndGen.GaussNormal<scalar>());
+    }
+
+    return mat;
+}
+
+
+// Copy an initializer list into a DiagonalMatrix
+template<class Type>
+void assignMatrix
+(
+    UList<Type>& A,
+    std::initializer_list<Type> list
+)
+{
+    std::copy(list.begin(), list.end(), A.begin());
+}
+
+
+// Copy an initializer list into a SymmetricSquareMatrix.
+template<class Form, class Type>
+void assignMatrix
+(
+    Matrix<Form, Type>& A,
+    std::initializer_list<typename Matrix<Form, Type>::cmptType> list
+)
+{
+    const label nargs = list.size();
+
+    if (nargs != A.size())
+    {
+        FatalErrorInFunction
+            << "Mismatch in matrix dimension ("
+            << A.m() << ", "
+            << A.n() << ") and number of args (" << nargs << ')' << nl
+            << exit(FatalError);
+     }
+
+    std::copy(list.begin(), list.end(), A.begin());
+}
+
+
+// Return a copy of the Matrix collapsed into one dimension.
+template<class Form, class Type>
+List<Type> flt
+(
+    const Matrix<Form, Type>& A,
+    const bool rowMajorOrder = true
+)
+{
+   List<Type> flatMatrix(A.size());
+
+   if (rowMajorOrder)
+   {
+       std::copy(A.cbegin(), A.cend(), flatMatrix.begin());
+   }
+   else
+   {
+       for (label j = 0; j < A.n(); ++j)
+       {
+           for (label i = 0; i < A.m(); ++i)
+           {
+               flatMatrix[i + j*A.m()] = A(i, j);
+           }
+       }
+   }
+
+   return flatMatrix;
+}
+
+
+// Compare two floating point types, and print output.
+// Do ++nFail_ if values of two objects are not equal within a given tolerance.
+// The function is converted from PEP-485.
+template<class Type>
+typename std::enable_if
+<
+    std::is_same<floatScalar, Type>::value ||
+    std::is_same<doubleScalar, Type>::value ||
+    std::is_same<complex, Type>::value,
+    void
+>::type cmp
+(
+    const word& msg,
+    const Type& x,
+    const Type& y,
+    const scalar absTol = 0,    //<! useful for cmps near zero
+    const scalar relTol = 1e-8  //<! are values the same within 8 decimals
+)
+{
+    Info<< msg << x << "?=" << y << endl;
+
+    unsigned nFail = 0;
+
+    if (max(absTol, relTol*max(mag(x), mag(y))) < mag(x - y))
+    {
+        ++nFail;
+    }
+
+    if (nFail)
+    {
+        Info<< nl
+            << "        #### Fail in " << nFail << " comps ####" << nl << endl;
+        ++nFail_;
+    }
+    ++nTest_;
+}
+
+
+// Compare two containers elementwise, and print output.
+// Do ++nFail_ if two components are not equal within a given tolerance.
+// The function is converted from PEP-485
+template<class Type>
+typename std::enable_if
+<
+    !std::is_same<floatScalar, Type>::value &&
+    !std::is_same<doubleScalar, Type>::value &&
+    !std::is_same<complex, Type>::value,
+    void
+>::type cmp
+(
+    const word& msg,
+    const Type& x,
+    const Type& y,
+    const scalar absTol = 0,
+    const scalar relTol = 1e-8
+)
+{
+    Info<< msg << x << "?=" << y << endl;
+
+    unsigned nFail = 0;
+
+    for (label i = 0; i < x.size(); ++i)
+    {
+        if (max(absTol, relTol*max(mag(x[i]), mag(y[i]))) < mag(x[i] - y[i]))
+        {
+            ++nFail;
+        }
+    }
+
+    if (nFail)
+    {
+        Info<< nl
+            << "        #### Fail in " << nFail << " comps ####" << nl << endl;
+        ++nFail_;
+    }
+    ++nTest_;
+}
+
+
+// Compare two containers elementwise, and print output.
+// Do ++nFail_ if two components are not equal within a given tolerance.
+// The function is converted from PEP-485
+template<class Type1, class Type2>
+typename std::enable_if
+<
+    !std::is_same<floatScalar, Type1>::value &&
+    !std::is_same<doubleScalar, Type1>::value &&
+    !std::is_same<complex, Type1>::value,
+    void
+>::type cmp
+(
+    const word& msg,
+    const Type1& x,
+    const Type2& y,
+    const scalar absTol = 0,
+    const scalar relTol = 1e-8
+)
+{
+    Info<< msg << x << "?=" << y << endl;
+
+    unsigned nFail = 0;
+
+    for (label i = 0; i < x.size(); ++i)
+    {
+        if (max(absTol, relTol*max(mag(x[i]), mag(y[i]))) < mag(x[i] - y[i]))
+        {
+            ++nFail;
+        }
+    }
+
+    if (nFail)
+    {
+        Info<< nl
+            << "        #### Fail in " << nFail << " comps ####" << nl << endl;
+        ++nFail_;
+    }
+    ++nTest_;
+}
+
+
+// Compare two Booleans, and print output.
+// Do ++nFail_ if two Booleans are not equal.
+void cmp
+(
+    const word& msg,
+    const bool x,
+    const bool y
+)
+{
+    Info<< msg << x << "?=" << y << endl;
+
+    unsigned nFail = 0;
+
+    if (x != y)
+    {
+        ++nFail;
+    }
+
+    if (nFail)
+    {
+        Info<< nl
+            << "        #### Fail in " << nFail << " comps ####" << nl << endl;
+        ++nFail_;
+    }
+    ++nTest_;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/matrices/DiagonalMatrix/Make/files b/applications/test/matrices/DiagonalMatrix/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..0f5877472a346b75694df94f6ff6b489c99cabdc
--- /dev/null
+++ b/applications/test/matrices/DiagonalMatrix/Make/files
@@ -0,0 +1,3 @@
+Test-DiagonalMatrix.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-DiagonalMatrix
diff --git a/applications/test/matrices/DiagonalMatrix/Make/options b/applications/test/matrices/DiagonalMatrix/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..b23590707c8d302fe75ce411d5bf921c029a7ff3
--- /dev/null
+++ b/applications/test/matrices/DiagonalMatrix/Make/options
@@ -0,0 +1,2 @@
+EXE_INC = -I../../TestTools
+/* EXE_LIBS = -lfiniteVolume */
diff --git a/applications/test/matrices/DiagonalMatrix/Test-DiagonalMatrix.C b/applications/test/matrices/DiagonalMatrix/Test-DiagonalMatrix.C
new file mode 100644
index 0000000000000000000000000000000000000000..3d8ae06979f579c8977c1fa3d216b42bc1034f46
--- /dev/null
+++ b/applications/test/matrices/DiagonalMatrix/Test-DiagonalMatrix.C
@@ -0,0 +1,231 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+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/>.
+
+Application
+    Test-DiagonalMatrix
+
+Description
+    Tests for \c DiagonalMatrix constructors, member functions and global
+    functions using \c floatScalar, \c doubleScalar, and \c complex base types.
+
+    Cross-checks were obtained from 'NumPy 1.15.1' if no theoretical
+    cross-check exists (like eigendecomposition relations), and
+    were hard-coded for elementwise comparisons.
+
+\*---------------------------------------------------------------------------*/
+
+#include "DiagonalMatrix.H"
+#include "RectangularMatrix.H"
+#include "floatScalar.H"
+#include "doubleScalar.H"
+#include "complex.H"
+#include "TestTools.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Create each constructor of DiagonalMatrix<Type>, and print output
+template<class Type>
+void test_constructors(Type)
+{
+    {
+        Info<< "# Construct empty from size:" << nl;
+        const DiagonalMatrix<Type> A(5);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct from size and initialise all elems to zero:" << nl;
+        const DiagonalMatrix<Type> A(5, Zero);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct from size and initialise all elems to value" << nl;
+        const DiagonalMatrix<Type> A(5, Type(8));
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct from the diagonal of a Matrix" << nl;
+        const RectangularMatrix<Type> M(3, 5, Zero);
+        const DiagonalMatrix<Type> A(M);
+        Info<< A << endl;
+    }
+}
+
+
+// Execute each member function of DiagonalMatrix<Type>, and print output
+template<class Type>
+void test_member_funcs(Type)
+{
+    DiagonalMatrix<Type> A(3, Zero);
+    assignMatrix(A, {Type(1), Type(2), Type(-3)});
+
+    Info<< "# Operand: " << nl
+        << "  DiagonalMatrix = " << A << endl;
+
+
+    {
+        Info<< "# Return the matrix inverse into itself:" << nl;
+        A.invert();
+        cmp
+        (
+            "  DiagonalMatrix<Type>.invert() = ",
+            A,
+            List<Type>({Type(1), Type(0.5), Type(-0.333333)}),
+            1e-6
+        );
+    }
+    {
+        Info<< "# Sort:" << nl;
+
+        DiagonalMatrix<Type> B(5, Zero);
+        assignMatrix(B, {Type(1), Type(2), Type(-3), Type(5), Type(1.01)});
+
+        auto descend = [&](Type a, Type b){ return mag(a) > mag(b); };
+        const List<label> sortPermutation(B.sortPermutation(descend));
+        cmp
+        (
+            "  Return a sort permutation labelList according to "
+            "a given comparison on the diagonal entries",
+            sortPermutation,
+            List<label>({3, 2, 1, 4, 0})
+        );
+
+        DiagonalMatrix<Type> sortedB0(5, Zero);
+        assignMatrix
+        (
+            sortedB0,
+            {
+                Type(5),
+                        Type(-3),
+                                 Type(2),
+                                         Type(1.01),
+                                                    Type(1)
+            }
+        );
+        const DiagonalMatrix<Type> sortedB1
+        (
+            applyPermutation(B, sortPermutation)
+        );
+        cmp
+        (
+            "  Return Matrix column-reordered according to "
+            "a given permutation labelList",
+            sortedB0,
+            sortedB1
+        );
+
+        DiagonalMatrix<Type> cpB(B);
+        cpB.applyPermutation(sortPermutation);
+        cmp
+        (
+            "  Column-reorder this Matrix according to "
+            "a given permutation labelList",
+            sortedB0,
+            cpB
+        );
+    }
+
+}
+
+
+// Execute each global function of DiagonalMatrix<Type>, and print output
+template<class Type>
+void test_global_funcs(Type)
+{
+    DiagonalMatrix<Type> A(3, Zero);
+    assignMatrix(A, {Type(1), Type(2), Type(-3)});
+
+    Info<< "# Operand: " << nl
+        << "  DiagonalMatrix = " << A << nl << endl;
+
+
+    cmp
+    (
+        "  Inverse = ",
+        inv(A),
+        List<Type>({Type(1), Type(0.5), Type(-0.333333)}),
+        1e-6
+    );
+}
+
+
+// Do compile-time recursion over the given types
+template<std::size_t I = 0, typename... Tp>
+inline typename std::enable_if<I == sizeof...(Tp), void>::type
+run_tests(const std::tuple<Tp...>& types, const List<word>& typeID){}
+
+
+template<std::size_t I = 0, typename... Tp>
+inline typename std::enable_if<I < sizeof...(Tp), void>::type
+run_tests(const std::tuple<Tp...>& types, const List<word>& typeID)
+{
+    Info<< nl << "    ## Test constructors: "<< typeID[I] <<" ##" << nl;
+    test_constructors(std::get<I>(types));
+
+    Info<< nl << "    ## Test member functions: "<< typeID[I] <<" ##" << nl;
+    test_member_funcs(std::get<I>(types));
+
+    Info<< nl << "    ## Test global functions: "<< typeID[I] << " ##" << nl;
+    test_global_funcs(std::get<I>(types));
+
+    run_tests<I + 1, Tp...>(types, typeID);
+}
+
+
+// * * * * * * * * * * * * * * * Main Program  * * * * * * * * * * * * * * * //
+
+int main()
+{
+    const std::tuple<floatScalar, doubleScalar, complex> types
+    (
+        std::make_tuple(Zero, Zero, Zero)
+    );
+
+    const List<word> typeID
+    ({
+        "DiagonalMatrix<floatScalar>",
+        "DiagonalMatrix<doubleScalar>",
+        "DiagonalMatrix<complex>"
+    });
+
+    run_tests(types, typeID);
+
+
+    if (nFail_)
+    {
+        Info<< nl << "        #### "
+            << "Failed in " << nFail_ << " tests "
+            << "out of total " << nTest_ << " tests "
+            << "####\n" << endl;
+        return 1;
+    }
+
+    Info<< nl << "        #### Passed all " << nTest_ <<" tests ####\n" << endl;
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/Matrix/Make/files b/applications/test/matrices/Matrix/Make/files
similarity index 100%
rename from applications/test/Matrix/Make/files
rename to applications/test/matrices/Matrix/Make/files
diff --git a/applications/test/Matrix/Make/options b/applications/test/matrices/Matrix/Make/options
similarity index 100%
rename from applications/test/Matrix/Make/options
rename to applications/test/matrices/Matrix/Make/options
diff --git a/applications/test/Matrix/Test-Matrix.C b/applications/test/matrices/Matrix/Test-Matrix.C
similarity index 99%
rename from applications/test/Matrix/Test-Matrix.C
rename to applications/test/matrices/Matrix/Test-Matrix.C
index 1cbc60254538df916b33a17d12bb5a579795fe18..43115df871371067f2ce87d5f1cf4a1905511c15 100644
--- a/applications/test/Matrix/Test-Matrix.C
+++ b/applications/test/matrices/Matrix/Test-Matrix.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
diff --git a/applications/test/QRMatrix/Make/files b/applications/test/matrices/QRMatrix/Make/files
similarity index 100%
rename from applications/test/QRMatrix/Make/files
rename to applications/test/matrices/QRMatrix/Make/files
diff --git a/applications/test/QRMatrix/Make/options b/applications/test/matrices/QRMatrix/Make/options
similarity index 100%
rename from applications/test/QRMatrix/Make/options
rename to applications/test/matrices/QRMatrix/Make/options
diff --git a/applications/test/QRMatrix/Test-QRMatrix.C b/applications/test/matrices/QRMatrix/Test-QRMatrix.C
similarity index 99%
rename from applications/test/QRMatrix/Test-QRMatrix.C
rename to applications/test/matrices/QRMatrix/Test-QRMatrix.C
index 281c62dd5b40dcd3d8983541fab42af31fc9608d..679072715257733728458b9f2810891f0fa04053 100644
--- a/applications/test/QRMatrix/Test-QRMatrix.C
+++ b/applications/test/matrices/QRMatrix/Test-QRMatrix.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -37,7 +37,6 @@ using namespace Foam::MatrixTools;
 #define RUNALL true
 const bool verbose = true;
 
-
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 void horizontalLine()
diff --git a/applications/test/matrices/RectangularMatrix/Make/files b/applications/test/matrices/RectangularMatrix/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..49b520d07986ab159a292f32f6f9455e5e12371e
--- /dev/null
+++ b/applications/test/matrices/RectangularMatrix/Make/files
@@ -0,0 +1,3 @@
+Test-RectangularMatrix.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-RectangularMatrix
diff --git a/applications/test/matrices/RectangularMatrix/Make/options b/applications/test/matrices/RectangularMatrix/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..b23590707c8d302fe75ce411d5bf921c029a7ff3
--- /dev/null
+++ b/applications/test/matrices/RectangularMatrix/Make/options
@@ -0,0 +1,2 @@
+EXE_INC = -I../../TestTools
+/* EXE_LIBS = -lfiniteVolume */
diff --git a/applications/test/matrices/RectangularMatrix/Test-RectangularMatrix.C b/applications/test/matrices/RectangularMatrix/Test-RectangularMatrix.C
new file mode 100644
index 0000000000000000000000000000000000000000..fbcf4c6343d72b70b7df298a22c2f41d9d9520c3
--- /dev/null
+++ b/applications/test/matrices/RectangularMatrix/Test-RectangularMatrix.C
@@ -0,0 +1,878 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+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/>.
+
+Application
+    Test-RectangularMatrix
+
+Description
+    Tests for \c RectangularMatrix constructors, member functions, member
+    operators, global functions, global operators, and friend functions using
+    \c floatScalar, \c doubleScalar, and \c complex base types.
+
+    Cross-checks were obtained from 'NumPy 1.15.1' if no theoretical
+    cross-check exists (like eigendecomposition relations), and
+    were hard-coded for elementwise comparisons.
+
+    For \c complex base type, the cross-checks do only involve zero imag part.
+
+Note
+    Pending tests were tagged as "## Pending ##".
+
+\*---------------------------------------------------------------------------*/
+
+#include "RectangularMatrix.H"
+#include "SquareMatrix.H"
+#include "floatScalar.H"
+#include "doubleScalar.H"
+#include "complex.H"
+#include "IOmanip.H"
+#include "TestTools.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Create each constructor of RectangularMatrix<Type>, and print output
+template<class Type>
+void test_constructors(Type)
+{
+    {
+        Info<< "# Construct a square matrix (rows == columns):" << nl;
+        const RectangularMatrix<Type> A(5);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct given number of rows/columns:" << nl;
+        const RectangularMatrix<Type> A(2, 4);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct given number of rows/columns "
+            << "initializing all elements to zero:" << nl;
+        const RectangularMatrix<Type> A(2, 4, Zero);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct given number of rows/columns "
+            << "initializing all elements to a value:" << nl;
+        const RectangularMatrix<Type> A(2, 4, Type(3));
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct given number of rows/columns "
+            << "initializing all elements to zero, and diagonal to one:" << nl;
+        const RectangularMatrix<Type> A(labelPair(2, 4), I);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct given number of rows/columns "
+            << "by using a label pair:" << nl;
+        const RectangularMatrix<Type> A(labelPair(2, 4));
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct given number of rows/columns by using a label pair "
+            << "and initializing all elements to zero:" << nl;
+        const RectangularMatrix<Type> A(labelPair(2, 4), Zero);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct given number of rows/columns by using a label pair "
+            << "and initializing all elements to the given value:" << nl;
+        const RectangularMatrix<Type> A(labelPair(2, 4), Type(3));
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct from a block of another matrix:" << nl;
+        const RectangularMatrix<Type> B(labelPair(2, 4), Type(3));
+        const RectangularMatrix<Type> A(B.subMatrix(1, 1));
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct from a block of another matrix:" << nl;
+        RectangularMatrix<Type> B(labelPair(2, 4), Type(3));
+        const RectangularMatrix<Type> A(B.subMatrix(1, 1));
+        Info<< A << endl;
+    }
+    {
+        Info<< "#: Construct as copy of a square matrix:" << nl;
+        const SquareMatrix<Type> B(5);
+        const RectangularMatrix<Type> A(B);
+        Info<< A << endl;
+    }
+}
+
+
+// Execute each member function of RectangularMatrix<Type>, and print output
+template<class Type>
+void test_member_funcs(Type)
+{
+    RectangularMatrix<Type> A(labelPair(2, 3), Zero);
+    assignMatrix
+    (
+        A,
+        {
+            Type(1), Type(-2.2), Type(-3.4),
+            Type(-0.35), Type(1), Type(5)
+        }
+    );
+
+    Info<< "# Operand: " << nl
+        << "  RectangularMatrix = " << A << endl;
+
+
+    // Matrix.H
+    {
+        Info<< "# Access:" << nl;
+
+        cmp("  The number of rows = ", Type(A.m()), Type(2));
+        cmp("  The number of columns = ", Type(A.n()), Type(3));
+        cmp("  The number of elements in Matrix = ", Type(A.size()), Type(6));
+        cmp("  Return row/column sizes = ", A.sizes(), labelPair(2, 3));
+        cmp("  Return true if Matrix is empty = ", A.empty(), false);
+        cmp
+        (
+            "  Return const pointer to the first data elem = ",
+            *(A.cdata()),
+            Type(1)
+        );
+        cmp
+        (
+            "  Return pointer to the first data elem = ",
+            *(A.data()),
+            Type(1)
+        );
+        cmp
+        (
+            "  Return const pointer to data in the specified row = ",
+            *(A.rowData(1)),
+            Type(-0.35)
+        );
+        cmp
+        (
+            "  Return pointer to data in the specified row = ",
+            *(A.rowData(1)),
+            Type(-0.35)
+        );
+        const Type& a = A.at(4);
+        cmp("  Linear addressing const element access = ", a, Type(1));
+        Type& b = A.at(4);
+        cmp("  Linear addressing element access = ", b, Type(1));
+    }
+    {
+        Info<< "# Block access (const):" << nl;
+
+        const RectangularMatrix<Type> Acol(A.subColumn(1));
+        cmp
+        (
+            "  Return const column or column's subset of Matrix = ",
+            flt(Acol),
+            List<Type>({Type(-2.2), Type(1)})
+        );
+
+        const RectangularMatrix<Type> Arow(A.subRow(1));
+        cmp
+        (
+            "  Return const row or row's subset of Matrix = ",
+            flt(Arow),
+            List<Type>({Type(-0.35), Type(1), Type(5)})
+        );
+
+        const RectangularMatrix<Type> Amat(A.subMatrix(1, 1));
+        cmp
+        (
+            "  Return const sub-block of Matrix = ",
+            flt(Amat),
+            List<Type>({Type(1), Type(5)})
+        );
+    }
+    {
+        Info<< "# Block access (non-const):" << nl;
+
+        RectangularMatrix<Type> Acol(A.subColumn(1));
+        cmp
+        (
+            "  Return column or column's subset of Matrix = ",
+            flt(Acol),
+            List<Type>({Type(-2.2), Type(1)})
+        );
+
+        RectangularMatrix<Type> Arow(A.subRow(1));
+        cmp
+        (
+            "  Return row or row's subset of Matrix = ",
+            flt(Arow),
+            List<Type>({Type(-0.35), Type(1), Type(5)})
+        );
+
+        RectangularMatrix<Type> Amat(A.subMatrix(1, 1));
+        cmp
+        (
+            "  Return sub-block of Matrix = ",
+            flt(Amat),
+            List<Type>({Type(1), Type(5)})
+        );
+    }
+    {
+        Info<< "# Check:" << nl;
+
+        A.checki(0);
+        A.checkj(1);
+        A.checkSize();
+        cmp("  Check all entries have identical values = ", A.uniform(), false);
+    }
+    {
+        Info<< "# Edit:" << nl;
+
+        RectangularMatrix<Type> cpA(A);
+        cpA.clear();
+        cmp("  Clear Matrix, i.e. set sizes to zero = ", cpA.empty(), true);
+
+        RectangularMatrix<Type> cpA1(A);
+        cmp
+        (
+            "  Release storage management of Matrix contents by transferring "
+            "management to a List = ",
+            (cpA1.release()),
+            List<Type>
+            ({
+                Type(1), Type(-2.2), Type(-3.4), Type(-0.35), Type(1), Type(5)
+            })
+        );
+
+        RectangularMatrix<Type> cpA2(A);
+        cpA2.swap(cpA1);
+        cmp("  Swap contents = ", flt(cpA1), flt(A));
+
+        cpA2.transfer(cpA1);
+        cmp
+        (
+            "  Transfer the contents of the argument Matrix into this Matrix "
+            "and annul the argument MatrixSwap contents = ",
+            flt(cpA2),
+            flt(A)
+        );
+
+        cpA2.resize(1, 2);
+        cmp
+        (
+            "  Change Matrix dimensions, preserving the elements = ",
+            flt(cpA2),
+            List<Type>({Type(1), Type(-2.2)})
+        );
+
+        RectangularMatrix<Type> cpA3(A);
+        cpA3.setSize(1, 2);
+        cmp
+        (
+            "  Change Matrix dimensions, preserving the elements = ",
+            flt(cpA3),
+            List<Type>({Type(1), Type(-2.2)})
+        );
+
+        RectangularMatrix<Type> cpA4(A);
+        cpA4.shallowResize(1, 2);
+        cmp
+        (
+            "  Resize Matrix without reallocating storage (unsafe) = ",
+            flt(cpA4),
+            List<Type>({Type(1), Type(-2.2)})
+        );
+
+        RectangularMatrix<Type> smallA(labelPair(2, 3), Type(VSMALL));
+        smallA.round();
+        cmp
+        (
+            "  Round elements with mag smaller than tol (SMALL) to zero = ",
+            flt(smallA),
+            List<Type>(6, Zero)
+        );
+    }
+    {
+        Info<< "# Operations:" << nl;
+
+        cmp("  Transpose = ", flt((A.T()).T()), flt(A));
+
+        RectangularMatrix<complex> cA(labelPair(2, 2), Zero);
+        assignMatrix
+        (
+            cA,
+            {
+                complex(2, -1.2), complex(4.1, 0.4),
+                complex(8.1, -1.25), complex(7.3, -1.4)
+            }
+        );
+        RectangularMatrix<complex> cAT(labelPair(2, 2), Zero);
+        assignMatrix
+        (
+            cAT,
+            {
+                complex(2, 1.2), complex(8.1, 1.25),
+                complex(4.1, -0.4), complex(7.3, 1.4)
+            }
+        );
+        cmp("  Hermitian transpose = ", flt(cA.T()), flt(cAT));
+
+        RectangularMatrix<Type> B(3, 3, Zero);
+        assignMatrix
+        (
+            B,
+            {
+                Type(4.1), Type(12.5), Type(-16.3),
+                Type(-192.3), Type(-9.1), Type(-3.0),
+                Type(1.0), Type(5.02), Type(-4.4)
+            }
+        );
+        const RectangularMatrix<Type> cpB(B);
+        const List<Type> lst({Type(1), Type(2), Type(3)});
+        const Field<Type> out1(B*lst);
+        const Field<Type> out2(B.Amul(lst));
+        const Field<Type> out3(lst*B);
+        const Field<Type> out4(B.Tmul(lst));
+        const Field<Type> rsult1({Type(-19.8), Type(-219.5), Type(-2.16)});
+        const Field<Type> rsult2({Type(-377.5), Type(9.36), Type(-35.5)});
+        cmp
+        (
+            "  Right-multiply Matrix by a List (A * x) = ",
+            out1,
+            rsult1,
+            1e-4
+        );
+        cmp
+        (
+            "  Right-multiply Matrix by a column vector A.Amul(x) = ",
+            out1,
+            out2,
+            1e-4
+        );
+        cmp
+        (
+            "  Left-multiply Matrix by a List (x * A) = ",
+            out3,
+            rsult2,
+            1e-4
+        );
+        cmp
+        (
+            "  Left-multiply Matrix by a row vector A.Tmul(x) = ",
+            out4,
+            rsult2,
+            1e-4
+        );
+
+        List<Type> diagB1({Type(4.1), Type(-9.1), Type(-4.4)});
+        cmp
+        (
+            "  Extract the diagonal elements = ",
+            B.diag(),
+            diagB1
+        );
+
+        List<Type> diagB2({Type(-100), Type(-100), Type(-100)});
+        B.diag(diagB2);
+        cmp
+        (
+            "  Assign diagonal of Matrix = ",
+            B.diag(),
+            diagB2
+        );
+
+        B = cpB;
+        cmp("  Trace = ", B.trace(), Type(-9.4), 1e-4);
+        cmp
+        (
+            "  Return L2-Norm of chosen column = ",
+            B.columnNorm(0),
+            192.34630227794867,
+            1e-4
+        );
+        cmp
+        (
+            "  Return L2-Norm of chosen column (noSqrt=true) = ",
+            B.columnNorm(0, true),
+            36997.1,
+            1e-2
+        );
+        cmp
+        (
+            "  Return Frobenius norm of Matrix = ",
+            B.norm(),
+            193.7921835369012,
+            1e-4
+        );
+    }
+}
+
+
+// Execute each member operators of RectangularMatrix<Type>, and print output
+template<class Type>
+void test_member_opers(Type)
+{
+    RectangularMatrix<Type> A(labelPair(2, 4), I);
+    const RectangularMatrix<Type> cpA(A);
+
+    Info<< "# Operand: " << nl
+        << "  RectangularMatrix = " << A << endl;
+
+
+    A = Zero;
+    cmp("  Assign all elements to zero =", flt(A), List<Type>(8, Zero));
+    A = cpA;
+
+    A = Type(5);
+    cmp("  Assign all elements to value =", flt(A), List<Type>(8, Type(5)));
+    A = cpA;
+
+    const Type* a = A[1];
+    cmp
+    (
+        "  Return const pointer to data in the specified row = ",
+        *a,
+        Type(0)
+    );
+
+    Type* b = A[1];
+    cmp
+    (
+        "  Return pointer to data in the specified row = ",
+        *b,
+        Type(0)
+    );
+
+    const Type& c = A(1, 1);
+    cmp
+    (
+        "  (i, j) const element access operator = ",
+        c,
+        Type(1)
+    );
+
+    Type& d = A(1, 1);
+    cmp
+    (
+        "  (i, j) element access operator = ",
+        d,
+        Type(1)
+    );
+
+    //  ## Pending ##
+    //  Copy assignment
+    //  Move assignment
+    //  Assignment to a block of another Matrix
+    //  Assignment to a block of another Matrix
+    //  #############
+
+    A = Zero;
+    cmp
+    (
+        "  Assignment of all elements to zero = ",
+        flt(A),
+        flt(RectangularMatrix<Type>(2, 4, Zero))
+    );
+    A = cpA;
+
+    A = Type(-1.2);
+    cmp
+    (
+        "  Assignment of all elements to the given value = ",
+        flt(A),
+        flt(RectangularMatrix<Type>(2, 4, Type(-1.2)))
+    );
+    A = cpA;
+
+    A += cpA;
+    cmp
+    (
+        "  Matrix addition =",
+        flt(A),
+        flt(Type(2)*cpA)
+    );
+    A = cpA;
+
+    A -= cpA;
+    cmp
+    (
+        "  Matrix subtraction = ",
+        flt(A),
+        flt(RectangularMatrix<Type>(2, 4, Zero))
+    );
+    A = cpA;
+
+    A = Zero;
+    A += Type(5);
+    cmp
+    (
+        "  Matrix scalar addition = ",
+        flt(A),
+        flt(RectangularMatrix<Type>(2, 4, Type(5)))
+    );
+    A = cpA;
+
+    A = Zero;
+    A -= Type(5);
+    cmp
+    (
+        "  Matrix scalar subtraction = ",
+        flt(A),
+        flt(RectangularMatrix<Type>(2, 4, Type(-5)))
+    );
+    A = cpA;
+
+    A = Type(1);
+    A *= Type(5);
+    cmp
+    (
+        "  Matrix scalar multiplication = ",
+        flt(A),
+        flt(RectangularMatrix<Type>(2, 4, Type(5)))
+    );
+    A = cpA;
+
+    A = Type(1);
+    A /= Type(5);
+    cmp
+    (
+        "  Matrix scalar division = ",
+        flt(A),
+        flt(RectangularMatrix<Type>(2, 4, Type(0.2)))
+    );
+    A = cpA;
+
+    A(0,0) = Type(-10.5);
+    Type* i0 = A.begin();
+    cmp
+    (
+        "  Return an iterator to begin traversing a Matrix = ",
+        *i0,
+        Type(-10.5)
+    );
+
+    A(1,3) = Type(20);
+    Type* i1 = A.end();
+    cmp
+    (
+        "  Return an iterator to end traversing a Matrix = ",
+        *(--i1),
+        Type(20)
+    );
+
+    const Type* i2 = A.cbegin();
+    cmp
+    (
+        "  Return const iterator to begin traversing a Matrix = ",
+        *i2,
+        Type(-10.5)
+    );
+
+    const Type* i3 = A.cend();
+    cmp
+    (
+        "  Return const iterator to end traversing a Matrix = ",
+        *(--i3),
+        Type(20)
+    );
+
+    const Type* i4 = A.begin();
+    cmp
+    (
+        "  Return const iterator to begin traversing a Matrix = ",
+        *i4,
+        Type(-10.5)
+    );
+
+    const Type* i5 = A.end();
+    cmp
+    (
+        "  Return const iterator to end traversing a Matrix = ",
+        *(--i5),
+        Type(20)
+    );
+
+    //  ## Pending ##
+    //  Read Matrix from Istream, discarding existing contents
+    //  Write Matrix, with line-breaks in ASCII when length exceeds shortLen
+    //  #############
+}
+
+
+// Execute each friend function of RectangularMatrix<Type>, and print output
+template<class Type>
+void test_friend_funcs(Type)
+{
+    const Field<Type> F
+    ({
+        Type(1), Type(-2.2),
+        Type(10), Type(-0.1)
+    });
+
+    Info<< "# Operand: " << nl
+        << "  Field = " << F << endl;
+
+    {
+        RectangularMatrix<Type> A(labelPair(4, 4), Zero);
+        assignMatrix
+        (
+            A,
+            {
+                Type(1), Type(-2.2), Type(10), Type(-0.1),
+                Type(-2.2), Type(4.84), Type(-22), Type(0.22),
+                Type(10), Type(-22), Type(100), Type(-1),
+                Type(-0.1), Type(0.22), Type(-1), Type(0.01)
+            }
+        );
+        cmp
+        (
+            "  Return the outer product of Field-Field as RectangularMatrix = ",
+            flt(outer(F, F)),
+            flt(A),
+            1e-6
+        );
+    }
+}
+
+
+// Execute each global function of RectangularMatrix<Type>, and print output
+template<class Type>
+void test_global_funcs(Type)
+{
+    RectangularMatrix<Type> A(labelPair(2, 3), Zero);
+    assignMatrix
+    (
+        A,
+        {
+            Type(1), Type(-2.2), Type(-3.4),
+            Type(-0.35), Type(10.32), Type(5)
+        }
+    );
+    const RectangularMatrix<Type> cpA(A);
+
+    Info<< "# Operand: " << nl
+        << "  RectangularMatrix = " << A << endl;
+
+
+    //  ## Pending ##
+    //  cmp("  Find max value in Matrix = ", max(A), Type(10.32));
+    //  cmp("  Find min value in Matrix = ", min(A), Type(-3.4));
+    //  cmp
+    //  (
+    //      "  Find min-max value in Matrix = ",
+    //      minMax(A),
+    //      MinMax<Type>(10.32, -3.4)
+    //  );
+    //  #############
+}
+
+
+// Execute each global operators of RectangularMatrix<Type>, and print output
+template<class Type>
+void test_global_opers(Type)
+{
+    RectangularMatrix<Type> A(labelPair(2, 3), Zero);
+    assignMatrix
+    (
+        A,
+        {
+            Type(1), Type(-2.2), Type(-3.4),
+            Type(-0.35), Type(10.32), Type(5)
+        }
+    );
+    const RectangularMatrix<Type> cpA(A);
+
+    Info<< "# Operand: " << nl
+        << "  RectangularMatrix = " << A << endl;
+
+
+    // Matrix.C
+    cmp("  Matrix negation = ", flt(-A), flt(Type(-1)*A));
+    cmp("  Matrix addition = ", flt(A + A), flt(Type(2)*A));
+    cmp("  Matrix subtraction = ", flt(A - A), flt(Type(0)*A));
+    cmp("  Scalar multiplication = ", flt(Type(2)*A), flt(A + A));
+    cmp("  Scalar multiplication = ", flt(A*Type(2)), flt(A + A));
+    cmp
+    (
+        "  Scalar addition = ",
+        flt(Type(0)*A + Type(1)),
+        flt(RectangularMatrix<Type>(A.sizes(), Type(1)))
+    );
+    cmp
+    (
+        "  Scalar addition = ",
+        flt(Type(1) + Type(0)*A),
+        flt(RectangularMatrix<Type>(A.sizes(), Type(1)))
+    );
+    cmp
+    (
+        "  Scalar subtraction = ",
+        flt(Type(0)*A - Type(1)),
+        flt(RectangularMatrix<Type>(A.sizes(), Type(-1)))
+    );
+    cmp
+    (
+        "  Scalar subtraction = ",
+        flt(Type(1) - Type(0)*A),
+        flt(RectangularMatrix<Type>(A.sizes(), Type(1)))
+    );
+    cmp
+    (
+        "  Scalar division = ",
+        flt((Type(1) + Type(0)*A)/Type(2.5)),
+        flt(RectangularMatrix<Type>(A.sizes(), Type(0.4)))
+    );
+
+    RectangularMatrix<Type> innerA(2, 2, Zero);
+    assignMatrix
+    (
+        innerA,
+        {
+            Type(17.4), Type(-40.054),
+            Type(-40.054), Type(131.6249)
+        }
+    );
+    const RectangularMatrix<Type> A1(A);
+    const RectangularMatrix<Type> A2(A.T());
+    cmp
+    (
+        "  Matrix-Matrix multiplication using ikj-algorithm = ",
+        flt(A1*A2),
+        flt(innerA),
+        1e-1
+    );
+    cmp
+    (
+        "  Implicit A.T()*B = ",
+        flt(A2&A2),
+        flt(innerA),
+        1e-1
+    );
+
+    RectangularMatrix<Type> outerA(3, 3, Zero);
+    assignMatrix
+    (
+        outerA,
+        {
+            Type(1.1225), Type(-5.812), Type(-5.15),
+            Type(-5.812), Type(111.3424), Type(59.08),
+            Type(-5.15), Type(59.08), Type(36.56)
+        }
+    );
+    cmp
+    (
+        "  Implicit A*B.T() = ",
+        flt(A2^A2),
+        flt(outerA),
+        1e-1
+    );
+
+    // MatrixI.H
+    const List<Type> lst({Type(1), Type(2), Type(-3)});
+    const List<Type> out1(A*lst);
+    const List<Type> out2(lst*A.T());
+    const List<Type> rslt1({Type(6.8), Type(5.29)});
+    const List<Type> rslt2({Type(6.8), Type(5.29)});
+    cmp
+    (
+        "  Matrix-vector multiplication (A * x), where x is a column vector = ",
+        out1,
+        rslt1,
+        1e-1
+    );
+    cmp
+    (
+        "  Vector-matrix multiplication (x * A), where x is a row vector = ",
+        out2,
+        rslt2,
+        1e-1
+    );
+}
+
+
+// Do compile-time recursion over the given types
+template<std::size_t I = 0, typename... Tp>
+inline typename std::enable_if<I == sizeof...(Tp), void>::type
+run_tests(const std::tuple<Tp...>& types, const List<word>& typeID){}
+
+
+template<std::size_t I = 0, typename... Tp>
+inline typename std::enable_if<I < sizeof...(Tp), void>::type
+run_tests(const std::tuple<Tp...>& types, const List<word>& typeID)
+{
+    Info<< nl << "    ## Test constructors: "<< typeID[I] <<" ##" << nl;
+    test_constructors(std::get<I>(types));
+
+    Info<< nl << "    ## Test member functions: "<< typeID[I] <<" ##" << nl;
+    test_member_funcs(std::get<I>(types));
+
+    Info<< nl << "    ## Test member opers: "<< typeID[I] <<" ##" << nl;
+    test_member_opers(std::get<I>(types));
+
+    Info<< nl << "    ## Test global functions: "<< typeID[I] << " ##" << nl;
+    test_global_funcs(std::get<I>(types));
+
+    Info<< nl << "    ## Test global operators: "<< typeID[I] << " ##" << nl;
+    test_global_opers(std::get<I>(types));
+
+    Info<< nl << "    ## Test friend funcs: "<< typeID[I] <<" ##" << nl;
+    test_friend_funcs(std::get<I>(types));
+
+    run_tests<I + 1, Tp...>(types, typeID);
+}
+
+
+// * * * * * * * * * * * * * * * Main Program  * * * * * * * * * * * * * * * //
+
+int main()
+{
+    Info<< setprecision(15);
+
+    const std::tuple<floatScalar, doubleScalar, complex> types
+    (
+        std::make_tuple(Zero, Zero, Zero)
+    );
+
+    const List<word> typeID
+    ({
+        "RectangularMatrix<floatScalar>",
+        "RectangularMatrix<doubleScalar>",
+        "RectangularMatrix<complex>"
+    });
+
+    run_tests(types, typeID);
+
+
+    if (nFail_)
+    {
+        Info<< nl << "        #### "
+            << "Failed in " << nFail_ << " tests "
+            << "out of total " << nTest_ << " tests "
+            << "####\n" << endl;
+        return 1;
+    }
+
+    Info<< nl << "        #### Passed all " << nTest_ <<" tests ####\n" << endl;
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/matrices/SquareMatrix/Make/files b/applications/test/matrices/SquareMatrix/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..e64b858cd6ba23bcc369939af81137b364927bdf
--- /dev/null
+++ b/applications/test/matrices/SquareMatrix/Make/files
@@ -0,0 +1,3 @@
+Test-SquareMatrix.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-SquareMatrix
diff --git a/applications/test/matrices/SquareMatrix/Make/options b/applications/test/matrices/SquareMatrix/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..b23590707c8d302fe75ce411d5bf921c029a7ff3
--- /dev/null
+++ b/applications/test/matrices/SquareMatrix/Make/options
@@ -0,0 +1,2 @@
+EXE_INC = -I../../TestTools
+/* EXE_LIBS = -lfiniteVolume */
diff --git a/applications/test/matrices/SquareMatrix/Test-SquareMatrix.C b/applications/test/matrices/SquareMatrix/Test-SquareMatrix.C
new file mode 100644
index 0000000000000000000000000000000000000000..d114dd39639e2ce3cc98a4a018d2ed3c3d6f6cd8
--- /dev/null
+++ b/applications/test/matrices/SquareMatrix/Test-SquareMatrix.C
@@ -0,0 +1,1000 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+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/>.
+
+Application
+    Test-SquareMatrix
+
+Description
+    Tests for \c SquareMatrix constructors, member functions, member
+    operators, global functions, global operators, and friend functions using
+    \c floatScalar, \c doubleScalar, and \c complex base types.
+
+    Cross-checks were obtained from 'NumPy 1.15.1' if no theoretical
+    cross-check exists (like eigendecomposition relations), and
+    were hard-coded for elementwise comparisons.
+
+    For \c complex base type, the cross-checks do only involve zero imag part.
+
+Note
+    Pending tests were tagged as "## Pending ##".
+
+\*---------------------------------------------------------------------------*/
+
+#include "scalarMatrices.H"
+#include "RectangularMatrix.H"
+#include "SquareMatrix.H"
+#include "floatScalar.H"
+#include "doubleScalar.H"
+#include "complex.H"
+#include "IOmanip.H"
+#include "TestTools.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Create each constructor of SquareMatrix<Type>, and print output
+template<class Type>
+void test_constructors(Type)
+{
+    {
+        Info<< "# Construct for given size (rows == cols):" << nl;
+        const SquareMatrix<Type> A(2);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct for given size (rows == cols) "
+            << "initializing all elements to zero:" << nl;
+        const SquareMatrix<Type> A(2, Zero);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct for given size (rows == cols) "
+            << "initializing all elements to a value:" << nl;
+        const SquareMatrix<Type> A(2, Type(3));
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct for given size (rows == cols) "
+            << "initializing to the identity matrix:" << nl;
+        const SquareMatrix<Type> A(2, I);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct for given size (rows == cols) by using a labelPair"
+            << "initializing to the identity matrix:" << nl;
+        const SquareMatrix<Type> A(labelPair(2, 2), I);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct given number of rows/columns "
+            << "by using a label pair (checked to be equal):" << nl;
+        const SquareMatrix<Type> A(labelPair(2, 2));
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct given number of rows/columns "
+            << "by using a label pair (checked to be equal) "
+            << "and initializing all elements to zero:" << nl;
+        const SquareMatrix<Type> A(labelPair(2, 2), Zero);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct given number of rows/columns "
+            << "by using a label pair (checked to be equal) "
+            << "and initializing all elements to the given value:" << nl;
+        const SquareMatrix<Type> A(labelPair(2, 2), Type(3));
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct given number of rows/columns "
+            << "(checked to be equal) initializing all elements to zero" << nl;
+        const SquareMatrix<Type> A(2, 2, Zero);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct from const sub-matrix block:" << nl;
+        const SquareMatrix<Type> B(labelPair(3, 3), Type(3));
+        const SquareMatrix<Type> A(B.subMatrix(1, 1));
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct from sub-matrix block:" << nl;
+        SquareMatrix<Type> B(labelPair(3, 3), Type(3));
+        const SquareMatrix<Type> A(B.subMatrix(1, 1));
+        Info<< A << endl;
+    }
+    {
+        Info<< "#: Construct as copy of a RectangularMatrix:" << nl;
+        const RectangularMatrix<Type> B(2, 2, Zero);
+        const SquareMatrix<Type> A(B);
+        Info<< A << endl;
+    }
+
+    //  ## Pending ##
+    //  Construct from Istream
+    //  Clone
+    //  #############
+}
+
+
+// Execute each member function of SquareMatrix<Type>, and print output
+template<class Type>
+void test_member_funcs(Type)
+{
+    SquareMatrix<Type> A(labelPair(3, 3), Zero);
+    assignMatrix
+    (
+        A,
+        {
+            Type(1), Type(-2.2), Type(-3.4),
+            Type(-0.35), Type(1), Type(5),
+            Type(-0.35), Type(1), Type(5)
+        }
+    );
+
+    Info<< "# Operand: " << nl
+        << "  SquareMatrix = " << A << endl;
+
+
+    {
+        Info<< "# Access:" << nl;
+
+        cmp("  The number of rows = ", Type(A.m()), Type(3));
+        cmp("  The number of columns = ", Type(A.n()), Type(3));
+        cmp("  The number of elements in Matrix = ", Type(A.size()), Type(9));
+        cmp("  Return row/column sizes = ", A.sizes(), labelPair(3, 3));
+        cmp("  Return true if Matrix is empty = ", A.empty(), false);
+        cmp
+        (
+            "  Return const pointer to the first data elem = ",
+            *(A.cdata()),
+            Type(1)
+        );
+        cmp
+        (
+            "  Return pointer to the first data elem = ",
+            *(A.data()),
+            Type(1)
+        );
+        cmp
+        (
+            "  Return const pointer to data in the specified row = ",
+            *(A.rowData(1)),
+            Type(-0.35)
+        );
+        cmp
+        (
+            "  Return pointer to data in the specified row = ",
+            *(A.rowData(1)),
+            Type(-0.35)
+        );
+        const Type& a = A.at(4);
+        cmp("  Linear addressing const element access = ", a, Type(1));
+        Type& b = A.at(4);
+        cmp("  Linear addressing element access = ", b, Type(1));
+    }
+    {
+        Info<< "# Block access (const):" << nl;
+
+        const RectangularMatrix<Type> Acol(A.subColumn(1));
+        cmp
+        (
+            "  Return const column or column's subset of Matrix = ",
+            flt(Acol),
+            List<Type>({Type(-2.2), Type(1), Type(1)})
+        );
+
+        const RectangularMatrix<Type> Arow(A.subRow(1));
+        cmp
+        (
+            "  Return const row or row's subset of Matrix = ",
+            flt(Arow),
+            List<Type>({Type(-0.35), Type(1), Type(5)})
+        );
+
+        const RectangularMatrix<Type> Amat(A.subMatrix(1, 1));
+        cmp
+        (
+            "  Return const sub-block of Matrix = ",
+            flt(Amat),
+            List<Type>({Type(1), Type(5), Type(1), Type(5)})
+        );
+    }
+    {
+        Info<< "# Block access (non-const):" << nl;
+
+        RectangularMatrix<Type> Acol(A.subColumn(1));
+        cmp
+        (
+            "  Return column or column's subset of Matrix = ",
+            flt(Acol),
+            List<Type>({Type(-2.2), Type(1), Type(1)})
+        );
+
+        RectangularMatrix<Type> Arow(A.subRow(1));
+        cmp
+        (
+            "  Return row or row's subset of Matrix = ",
+            flt(Arow),
+            List<Type>({Type(-0.35), Type(1), Type(5)})
+        );
+
+        RectangularMatrix<Type> Amat(A.subMatrix(1, 1));
+        cmp
+        (
+            "  Return sub-block of Matrix = ",
+            flt(Amat),
+            List<Type>({Type(1), Type(5), Type(1), Type(5)})
+        );
+    }
+    {
+        Info<< "# Check:" << nl;
+
+        A.checki(0);
+        A.checkj(1);
+        A.checkSize();
+        cmp("  Check all entries have identical values = ", A.uniform(), false);
+
+        {
+            Random rndGen(1234);
+            const label mRows = 10;
+            SquareMatrix<Type> B
+            (
+                makeRandomMatrix<SquareMatrix<Type>>(labelPair(mRows, mRows), rndGen)
+            );
+            // Symmetrise
+            for (label n = 0; n < B.n() - 1; ++n)
+            {
+                for (label m = B.m() - 1; n < m; --m)
+                {
+                    B(n, m) = B(m, n);
+                }
+            }
+            cmp
+            (
+                "  Return true if the square matrix is "
+                "effectively symmetric/Hermitian",
+                B.symmetric(),
+                true
+            );
+        }
+        //  ## Pending ##
+        //  Return true if the square matrix is reduced tridiagonal
+        //  #############
+    }
+    {
+        Info<< "# Edit:" << nl;
+
+        SquareMatrix<Type> cpA0(A);
+        cpA0.clear();
+        cmp("  Clear Matrix, i.e. set sizes to zero = ", cpA0.empty(), true);
+
+        SquareMatrix<Type> cpA1(A);
+        cmp
+        (
+            "  Release storage management of Matrix contents by transferring "
+            "management to a List = ",
+            (cpA1.release()),
+            List<Type>
+            ({
+                Type(1), Type(-2.2), Type(-3.4),
+                Type(-0.35), Type(1), Type(5),
+                Type(-0.35), Type(1), Type(5)
+            })
+        );
+
+        SquareMatrix<Type> cpA2(A);
+        cpA2.swap(cpA1);
+        cmp("  Swap contents = ", flt(cpA1), flt(A));
+
+        cpA2.transfer(cpA1);
+        cmp
+        (
+            "  Transfer the contents of the argument Matrix into this Matrix "
+            "and annul the argument MatrixSwap contents = ",
+            flt(cpA2),
+            flt(A)
+        );
+
+        cpA2.resize(2, 2);
+        cmp
+        (
+            "  Change Matrix dimensions, preserving the elements = ",
+            flt(cpA2),
+            List<Type>({Type(1), Type(-2.2), Type(-0.35), Type(1)})
+        );
+
+        cpA2.resize(1);
+        cmp
+        (
+            "  Resize the matrix preserving the elements = ",
+            flt(cpA2),
+            List<Type>({Type(1)})
+        );
+
+        SquareMatrix<Type> cpA3(A);
+        cpA3.setSize(2);
+        cmp
+        (
+            "  Resize the matrix preserving the elements = ",
+            flt(cpA3),
+            List<Type>({Type(1), Type(-2.2), Type(-0.35), Type(1)})
+        );
+
+        SquareMatrix<Type> cpA4(A);
+        cpA4.shallowResize(2);
+        cmp
+        (
+            "  Resize the matrix without reallocating storage (unsafe) = ",
+            flt(cpA4),
+            List<Type>({Type(1), Type(-2.2), Type(-3.4), Type(-0.35)})
+        );
+
+        SquareMatrix<Type> smallA(2, Type(VSMALL));
+        smallA.round();
+        cmp
+        (
+            "  Round elements with mag smaller than tol (SMALL) to zero = ",
+            flt(smallA),
+            List<Type>(4, Zero)
+        );
+    }
+    {
+        Info<< "# Sort:" << nl;
+
+        SquareMatrix<Type> cpA(A);
+        auto descend = [&](Type a, Type b){ return mag(a) > mag(b); };
+        const List<label> sortPermutation(cpA.sortPermutation(descend));
+        cmp
+        (
+            "  Return a sort permutation labelList according to "
+            "a given comparison on the diagonal entries",
+            sortPermutation,
+            List<label>({2, 0, 1})
+        );
+
+        SquareMatrix<Type> sortedA0(3, Zero);
+        assignMatrix
+        (
+            sortedA0,
+            {
+                Type(-3.4), Type(1),     Type(-2.2),
+                Type(5),    Type(-0.35), Type(1),
+                Type(5),    Type(-0.35), Type(1)
+            }
+        );
+        const SquareMatrix<Type> sortedA1(applyPermutation(A, sortPermutation));
+        cmp
+        (
+            "  Return Matrix column-reordered according to "
+            "a given permutation labelList",
+            flt(sortedA0),
+            flt(sortedA1)
+        );
+
+        cpA.applyPermutation(sortPermutation);
+        cmp
+        (
+            "  Column-reorder this Matrix according to "
+            "a given permutation labelList",
+            flt(sortedA0),
+            flt(cpA)
+        );
+    }
+    {
+        Info<< "# Operations:" << nl;
+
+        cmp("  Transpose = ", flt((A.T()).T()), flt(A));
+
+        SquareMatrix<complex> cA(labelPair(2, 2), Zero);
+        assignMatrix
+        (
+            cA,
+            {
+                complex(2, -1.2), complex(4.1, 0.4),
+                complex(8.1, -1.25), complex(7.3, -1.4)
+            }
+        );
+        SquareMatrix<complex> cAT(labelPair(2, 2), Zero);
+        assignMatrix
+        (
+            cAT,
+            {
+                complex(2, 1.2), complex(8.1, 1.25),
+                complex(4.1, -0.4), complex(7.3, 1.4)
+            }
+        );
+        cmp("  Hermitian transpose = ", flt(cA.T()), flt(cAT));
+
+        SquareMatrix<Type> B(3, 3, Zero);
+        assignMatrix
+        (
+            B,
+            {
+                Type(4.1), Type(12.5), Type(-16.3),
+                Type(-192.3), Type(-9.1), Type(-3.0),
+                Type(1.0), Type(5.02), Type(-4.4)
+            }
+        );
+        const SquareMatrix<Type> cpB(B);
+        const List<Type> lst({Type(1), Type(2), Type(3)});
+        const Field<Type> out1(B*lst);
+        const Field<Type> out2(B.Amul(lst));
+        const Field<Type> out3(lst*B);
+        const Field<Type> out4(B.Tmul(lst));
+        const Field<Type> rsult1({Type(-19.8), Type(-219.5), Type(-2.16)});
+        const Field<Type> rsult2({Type(-377.5), Type(9.36), Type(-35.5)});
+        cmp
+        (
+            "  Right-multiply Matrix by a List (A * x) = ",
+            out1,
+            rsult1,
+            1e-4
+        );
+        cmp
+        (
+            "  Right-multiply Matrix by a column vector A.Amul(x) = ",
+            out1,
+            out2,
+            1e-4
+        );
+        cmp
+        (
+            "  Left-multiply Matrix by a List (x * A) = ",
+            out3,
+            rsult2,
+            1e-4
+        );
+        cmp
+        (
+            "  Left-multiply Matrix by a row vector A.Tmul(x) = ",
+            out4,
+            rsult2,
+            1e-4
+        );
+
+        List<Type> diagB1({Type(4.1), Type(-9.1), Type(-4.4)});
+        cmp
+        (
+            "  Extract the diagonal elements = ",
+            B.diag(),
+            diagB1
+        );
+
+        List<Type> diagB2({Type(-100), Type(-100), Type(-100)});
+        B.diag(diagB2);
+        cmp
+        (
+            "  Assign diagonal of Matrix = ",
+            B.diag(),
+            diagB2
+        );
+
+        B = cpB;
+        cmp("  Trace = ", B.trace(), Type(-9.4), 1e-4);
+        cmp
+        (
+            "  Return L2-Norm of chosen column = ",
+            B.columnNorm(0),
+            192.34630227794867,
+            1e-4
+        );
+        cmp
+        (
+            "  Return L2-Norm of chosen column (noSqrt=true) = ",
+            B.columnNorm(0, true),
+            36997.1,
+            1e-2
+        );
+        cmp
+        (
+            "  Return Frobenius norm of Matrix = ",
+            B.norm(),
+            193.7921835369012,
+            1e-4
+        );
+
+
+    }
+}
+
+
+// Execute each member operators of SquareMatrix<Type>, and print output
+template<class Type>
+void test_member_opers(Type)
+{
+    SquareMatrix<Type> A(3, I);
+    const SquareMatrix<Type> cpA(A);
+
+    Info<< "# Operand: " << nl
+        << "  SquareMatrix = " << A << endl;
+
+
+    A = Zero;
+    cmp("  Assign all elements to zero =", flt(A), List<Type>(9, Zero));
+    A = cpA;
+
+    A = Type(5);
+    cmp("  Assign all elements to value =", flt(A), List<Type>(9, Type(5)));
+    A = cpA;
+
+    A = I;
+    cmp("  Set to identity matrix =", flt(A), flt(cpA));
+    A = cpA;
+
+    const Type* a = A[1];
+    cmp
+    (
+        "  Return const pointer to data in the specified row = ",
+        *a,
+        Type(0)
+    );
+
+    Type* b = A[1];
+    cmp
+    (
+        "  Return pointer to data in the specified row = ",
+        *b,
+        Type(0)
+    );
+
+    const Type& c = A(1, 1);
+    cmp
+    (
+        "  (i, j) const element access operator = ",
+        c,
+        Type(1)
+    );
+
+    Type& d = A(1, 1);
+    cmp
+    (
+        "  (i, j) element access operator = ",
+        d,
+        Type(1)
+    );
+
+    //  ## Pending ##
+    //  Copy assignment
+    //  Move assignment
+    //  Assignment to a block of another Matrix
+    //  Assignment to a block of another Matrix
+    //  #############
+
+    A = Zero;
+    cmp
+    (
+        "  Assignment of all elements to zero = ",
+        flt(A),
+        flt(SquareMatrix<Type>(3, Zero))
+    );
+    A = cpA;
+
+    A = Type(-1.2);
+    cmp
+    (
+        "  Assignment of all elements to the given value = ",
+        flt(A),
+        flt(SquareMatrix<Type>(3, Type(-1.2)))
+    );
+    A = cpA;
+
+    A += cpA;
+    cmp
+    (
+        "  Matrix addition =",
+        flt(A),
+        flt(Type(2)*cpA)
+    );
+    A = cpA;
+
+    A -= cpA;
+    cmp
+    (
+        "  Matrix subtraction = ",
+        flt(A),
+        flt(SquareMatrix<Type>(3, Zero))
+    );
+    A = cpA;
+
+    A = Zero;
+    A += Type(5);
+    cmp
+    (
+        "  Matrix scalar addition = ",
+        flt(A),
+        flt(SquareMatrix<Type>(3, Type(5)))
+    );
+    A = cpA;
+
+    A = Zero;
+    A -= Type(5);
+    cmp
+    (
+        "  Matrix scalar subtraction = ",
+        flt(A),
+        flt(SquareMatrix<Type>(3, Type(-5)))
+    );
+    A = cpA;
+
+    A = Type(1);
+    A *= Type(5);
+    cmp
+    (
+        "  Matrix scalar multiplication = ",
+        flt(A),
+        flt(SquareMatrix<Type>(3, Type(5)))
+    );
+    A = cpA;
+
+    A = Type(1);
+    A /= Type(5);
+    cmp
+    (
+        "  Matrix scalar division = ",
+        flt(A),
+        flt(SquareMatrix<Type>(3, Type(0.2)))
+    );
+    A = cpA;
+
+    A(0,0) = Type(-10.5);
+    Type* i0 = A.begin();
+    cmp
+    (
+        "  Return an iterator to begin traversing a Matrix = ",
+        *i0,
+        Type(-10.5)
+    );
+
+    A(2,2) = Type(20);
+    Type* i1 = A.end();
+    cmp
+    (
+        "  Return an iterator to end traversing a Matrix = ",
+        *(--i1),
+        Type(20)
+    );
+
+    const Type* i2 = A.cbegin();
+    cmp
+    (
+        "  Return const iterator to begin traversing a Matrix = ",
+        *i2,
+        Type(-10.5)
+    );
+
+    const Type* i3 = A.cend();
+    cmp
+    (
+        "  Return const iterator to end traversing a Matrix = ",
+        *(--i3),
+        Type(20)
+    );
+
+    const Type* i4 = A.begin();
+    cmp
+    (
+        "  Return const iterator to begin traversing a Matrix = ",
+        *i4,
+        Type(-10.5)
+    );
+
+    const Type* i5 = A.end();
+    cmp
+    (
+        "  Return const iterator to end traversing a Matrix = ",
+        *(--i5),
+        Type(20)
+    );
+
+    //  ## Pending ##
+    //  Read Matrix from Istream, discarding existing contents
+    //  Write Matrix, with line-breaks in ASCII when length exceeds shortLen
+    //  #############
+}
+
+
+// Execute each friend function of SquareMatrix<Type>, and print output
+template<class Type>
+void test_friend_funcs(Type)
+{
+    const Field<Type> F
+    ({
+        Type(1), Type(-2.2),
+        Type(10), Type(-0.1)
+    });
+
+    Info<< "# Operand: " << nl
+        << "  Field = " << F << endl;
+
+    {
+        SquareMatrix<Type> A(labelPair(4, 4), Zero);
+        assignMatrix
+        (
+            A,
+            {
+                Type(1), Type(-2.2), Type(10), Type(-0.1),
+                Type(-2.2), Type(4.84), Type(-22), Type(0.22),
+                Type(10), Type(-22), Type(100), Type(-1),
+                Type(-0.1), Type(0.22), Type(-1), Type(0.01)
+            }
+        );
+        cmp
+        (
+            "  Return the outer product of Field-Field as RectangularMatrix = ",
+            flt(outer(F, F)),
+            flt(A),
+            1e-6
+        );
+        cmp
+        (
+            "  Return the outer product of Field-Field as SquareMatrix = ",
+            flt(symmOuter(F, F)),
+            flt(A),
+            1e-6
+        );
+    }
+}
+
+
+// Execute each global function of SquareMatrix<Type>, and print output
+template<class Type>
+void test_global_funcs(Type)
+{
+    SquareMatrix<Type> A(3, Zero);
+    assignMatrix
+    (
+        A,
+        {
+            Type(1), Type(-2.2), Type(-3.4),
+            Type(-0.35), Type(10.32), Type(5),
+            Type(-0.35), Type(10.32), Type(-5)
+        }
+    );
+    const SquareMatrix<Type> cpA(A);
+
+    Info<< "# Operand: " << nl
+        << "  SquareMatrix = " << A << endl;
+
+    //  ## Pending ##: 'LUDecompose' does not operate with 'complex' base type
+    //  cmp
+    //  (
+    //      "  Return the determinant of SquareMatrix",
+    //      det(A),
+    //      -95.5
+    //  );
+    //  #############
+
+    //  ## Pending ##
+    //  cmp("  Find max value in Matrix = ", max(A), Type(10.32));
+    //  cmp("  Find min value in Matrix = ", min(A), Type(-3.4));
+    //  cmp
+    //  (
+    //      "  Find min-max value in Matrix = ",
+    //      minMax(A),
+    //      MinMax<Type>(10.32, -3.4)
+    //  );
+    //  #############
+}
+
+
+// Execute each global operators of SquareMatrix<Type>, and print output
+template<class Type>
+void test_global_opers(Type)
+{
+    SquareMatrix<Type> A(3, Zero);
+    assignMatrix
+    (
+        A,
+        {
+            Type(1), Type(-2.2), Type(-3.4),
+            Type(-0.35), Type(10.32), Type(5),
+            Type(-0.35), Type(10.32), Type(-5)
+        }
+    );
+    const SquareMatrix<Type> cpA(A);
+
+    Info<< "# Operand: " << nl
+        << "  SquareMatrix = " << A << endl;
+
+
+    cmp("  Matrix negation = ", flt(-A), flt(Type(-1)*A));
+    cmp("  Matrix addition = ", flt(A + A), flt(Type(2)*A));
+    cmp("  Matrix subtraction = ", flt(A - A), flt(Type(0)*A));
+    cmp("  Scalar multiplication = ", flt(Type(2)*A), flt(A + A));
+    cmp("  Scalar multiplication = ", flt(A*Type(2)), flt(A + A));
+    cmp
+    (
+        "  Scalar addition = ",
+        flt(Type(0)*A + Type(1)),
+        flt(SquareMatrix<Type>(A.sizes(), Type(1)))
+    );
+    cmp
+    (
+        "  Scalar addition = ",
+        flt(Type(1) + Type(0)*A),
+        flt(SquareMatrix<Type>(A.sizes(), Type(1)))
+    );
+    cmp
+    (
+        "  Scalar subtraction = ",
+        flt(Type(0)*A - Type(1)),
+        flt(SquareMatrix<Type>(A.sizes(), Type(-1)))
+    );
+    cmp
+    (
+        "  Scalar subtraction = ",
+        flt(Type(1) - Type(0)*A),
+        flt(SquareMatrix<Type>(A.sizes(), Type(1)))
+    );
+    cmp
+    (
+        "  Scalar division = ",
+        flt((Type(1) + Type(0)*A)/Type(2.5)),
+        flt(SquareMatrix<Type>(A.sizes(), Type(0.4)))
+    );
+
+    SquareMatrix<Type> A1(3, Zero);
+    assignMatrix
+    (
+        A1,
+        {
+            Type(2.9600), Type(-59.9920), Type(2.6000),
+            Type(-5.71199), Type(158.87239), Type(27.789997),
+            Type(-2.211999), Type(55.672393), Type(77.789993)
+        }
+    );
+    cmp
+    (
+        "  Matrix-Matrix multiplication using ikj-algorithm = ",
+        flt(A*A),
+        flt(A1),
+        1e-4
+    );
+    SquareMatrix<Type> A2(3, Zero);
+    assignMatrix
+    (
+        A2,
+        {
+            Type(1.245), Type(-9.424), Type(-3.4),
+            Type(-9.424), Type(217.8448), Type(7.47999),
+            Type(-3.4), Type(7.47999), Type(61.56)
+        }
+    );
+    cmp
+    (
+        "  Implicit A.T()*B = ",
+        flt(A&A),
+        flt(A2),
+        1e-4
+    );
+    SquareMatrix<Type> A3(3, Zero);
+    assignMatrix
+    (
+        A3,
+        {
+            Type(17.4), Type(-40.054), Type(-6.054),
+            Type(-40.054), Type(131.6249), Type(81.6249),
+            Type(-6.054), Type(81.6249), Type(131.6249)
+        }
+    );
+    cmp
+    (
+        "  Implicit A*B.T() = ",
+        flt(A^A),
+        flt(A3),
+        1e-4
+    );
+
+    const List<Type> lst({Type(1), Type(2), Type(-3)});
+    const List<Type> out1(A*lst);
+    const List<Type> out2(lst*A);
+    const List<Type> rslt1({Type(6.7999), Type(5.2900), Type(35.29)});
+    const List<Type> rslt2({Type(1.35), Type(-12.52), Type(21.6)});
+    cmp
+    (
+        "  Matrix-vector multiplication (A * x), where x is a column vector = ",
+        out1,
+        rslt1,
+        1e-2
+    );
+    cmp
+    (
+        "  Vector-matrix multiplication (x * A), where x is a row vector = ",
+        out2,
+        rslt2,
+        1e-4
+    );
+}
+
+
+// Do compile-time recursion over the given types
+template<std::size_t I = 0, typename... Tp>
+inline typename std::enable_if<I == sizeof...(Tp), void>::type
+run_tests(const std::tuple<Tp...>& types, const List<word>& typeID){}
+
+
+template<std::size_t I = 0, typename... Tp>
+inline typename std::enable_if<I < sizeof...(Tp), void>::type
+run_tests(const std::tuple<Tp...>& types, const List<word>& typeID)
+{
+    Info<< nl << "    ## Test constructors: "<< typeID[I] <<" ##" << nl;
+    test_constructors(std::get<I>(types));
+
+    Info<< nl << "    ## Test member functions: "<< typeID[I] <<" ##" << nl;
+    test_member_funcs(std::get<I>(types));
+
+    Info<< nl << "    ## Test member opers: "<< typeID[I] <<" ##" << nl;
+    test_member_opers(std::get<I>(types));
+
+    Info<< nl << "    ## Test global functions: "<< typeID[I] << " ##" << nl;
+    test_global_funcs(std::get<I>(types));
+
+    Info<< nl << "    ## Test global operators: "<< typeID[I] << " ##" << nl;
+    test_global_opers(std::get<I>(types));
+
+    Info<< nl << "    ## Test friend funcs: "<< typeID[I] <<" ##" << nl;
+    test_friend_funcs(std::get<I>(types));
+
+    run_tests<I + 1, Tp...>(types, typeID);
+}
+
+
+// * * * * * * * * * * * * * * * Main Program  * * * * * * * * * * * * * * * //
+
+int main()
+{
+    Info<< setprecision(15);
+
+    const std::tuple<floatScalar, doubleScalar, complex> types
+    (
+        std::make_tuple(Zero, Zero, Zero)
+    );
+
+    const List<word> typeID
+    ({
+        "SquareMatrix<floatScalar>",
+        "SquareMatrix<doubleScalar>",
+        "SquareMatrix<complex>"
+    });
+
+    run_tests(types, typeID);
+
+    if (nFail_)
+    {
+        Info<< nl << "        #### "
+            << "Failed in " << nFail_ << " tests "
+            << "out of total " << nTest_ << " tests "
+            << "####\n" << endl;
+        return 1;
+    }
+
+    Info<< nl << "        #### Passed all " << nTest_ <<" tests ####\n" << endl;
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/matrices/SymmetricSquareMatrix/Make/files b/applications/test/matrices/SymmetricSquareMatrix/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..da88933c249e3bfafd2a25c4842babc8f5c5c1f5
--- /dev/null
+++ b/applications/test/matrices/SymmetricSquareMatrix/Make/files
@@ -0,0 +1,3 @@
+Test-SymmetricSquareMatrix.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-SymmetricSquareMatrix
diff --git a/applications/test/matrices/SymmetricSquareMatrix/Make/options b/applications/test/matrices/SymmetricSquareMatrix/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..b23590707c8d302fe75ce411d5bf921c029a7ff3
--- /dev/null
+++ b/applications/test/matrices/SymmetricSquareMatrix/Make/options
@@ -0,0 +1,2 @@
+EXE_INC = -I../../TestTools
+/* EXE_LIBS = -lfiniteVolume */
diff --git a/applications/test/matrices/SymmetricSquareMatrix/Test-SymmetricSquareMatrix.C b/applications/test/matrices/SymmetricSquareMatrix/Test-SymmetricSquareMatrix.C
new file mode 100644
index 0000000000000000000000000000000000000000..c3d47e59b08e4794f2d3ec3f7998d61b62102ff2
--- /dev/null
+++ b/applications/test/matrices/SymmetricSquareMatrix/Test-SymmetricSquareMatrix.C
@@ -0,0 +1,207 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+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/>.
+
+Application
+    Test-SymmetricSquareMatrix
+
+Description
+    Tests for \c SymmetricSquareMatrix constructors, member functions, member
+    operators, global functions, global operators, and friend functions using
+    \c floatScalar, \c doubleScalar, and \c complex base types.
+
+    Cross-checks were obtained from 'NumPy 1.15.1' if no theoretical
+    cross-check exists (like eigendecomposition relations), and
+    were hard-coded for elementwise comparisons.
+
+    For \c complex base type, the cross-checks do only involve zero imag part.
+
+Note
+    Pending tests were tagged as "## Pending ##".
+
+\*---------------------------------------------------------------------------*/
+
+#include "scalarMatrices.H"
+#include "RectangularMatrix.H"
+#include "SquareMatrix.H"
+#include "SymmetricSquareMatrix.H"
+#include "floatScalar.H"
+#include "doubleScalar.H"
+#include "complex.H"
+#include "IOmanip.H"
+#include "Random.H"
+#include "TestTools.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Create each constructor of SymmetricSquareMatrix<Type>, and print output
+template<class Type>
+void test_constructors(Type)
+{
+    {
+        Info<< "# Construct for given size (rows == cols):" << nl;
+        const SymmetricSquareMatrix<Type> A(2);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct for given size (rows == cols) "
+            << "initializing all elements to zero:" << nl;
+        const SymmetricSquareMatrix<Type> A(2, Zero);
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct for given size (rows == cols) "
+            << "initializing all elements to a value:" << nl;
+        const SymmetricSquareMatrix<Type> A(2, Type(3));
+        Info<< A << endl;
+    }
+    {
+        Info<< "# Construct for given size (rows == cols) "
+            << "initializing to the identity matrix:" << nl;
+        const SymmetricSquareMatrix<Type> A(2, I);
+        Info<< A << endl;
+    }
+
+    //  ## Pending ##
+    //  Construct from Istream
+    //  Clone
+    //  #############
+}
+
+
+// Execute each member function of SymmetricSquareMatrix<Type>, and print output
+template<class Type>
+void test_member_funcs(Type)
+{
+    //  ## Pending ##
+    //  #############
+}
+
+
+// Execute each member operators of SymmetricSquareMatrix<Type>, and print output
+template<class Type>
+void test_member_opers(Type)
+{
+    //  ## Pending ##
+    //  #############
+}
+
+
+// Execute each friend function of SymmetricSquareMatrix<Type>, and print output
+template<class Type>
+void test_friend_funcs(Type)
+{
+    //  ## Pending ##
+    //  #############
+}
+
+
+// Execute each global function of SymmetricSquareMatrix<Type>, and print output
+template<class Type>
+void test_global_funcs(Type)
+{
+    //  ## Pending ##
+    //  #############
+}
+
+
+// Execute each global operators of SymmetricSquareMatrix<Type>, and print output
+template<class Type>
+void test_global_opers(Type)
+{
+    //  ## Pending ##
+    //  #############
+}
+
+
+// Do compile-time recursion over the given types
+template<std::size_t I = 0, typename... Tp>
+inline typename std::enable_if<I == sizeof...(Tp), void>::type
+run_tests(const std::tuple<Tp...>& types, const List<word>& typeID){}
+
+
+template<std::size_t I = 0, typename... Tp>
+inline typename std::enable_if<I < sizeof...(Tp), void>::type
+run_tests(const std::tuple<Tp...>& types, const List<word>& typeID)
+{
+    Info<< nl << "    ## Test constructors: "<< typeID[I] <<" ##" << nl;
+    test_constructors(std::get<I>(types));
+
+    Info<< nl << "    ## Test member functions: "<< typeID[I] <<" ##" << nl;
+    test_member_funcs(std::get<I>(types));
+
+    Info<< nl << "    ## Test member opers: "<< typeID[I] <<" ##" << nl;
+    test_member_opers(std::get<I>(types));
+
+    Info<< nl << "    ## Test global functions: "<< typeID[I] << " ##" << nl;
+    test_global_funcs(std::get<I>(types));
+
+    Info<< nl << "    ## Test global operators: "<< typeID[I] << " ##" << nl;
+    test_global_opers(std::get<I>(types));
+
+    Info<< nl << "    ## Test friend funcs: "<< typeID[I] <<" ##" << nl;
+    test_friend_funcs(std::get<I>(types));
+
+    run_tests<I + 1, Tp...>(types, typeID);
+}
+
+
+// * * * * * * * * * * * * * * * Main Program  * * * * * * * * * * * * * * * //
+
+int main()
+{
+    Info<< setprecision(15);
+
+    const std::tuple<floatScalar, doubleScalar, complex> types
+    (
+        std::make_tuple(Zero, Zero, Zero)
+    );
+
+    const List<word> typeID
+    ({
+        "SymmetricSquareMatrix<floatScalar>",
+        "SymmetricSquareMatrix<doubleScalar>",
+        "SymmetricSquareMatrix<complex>"
+    });
+
+    run_tests(types, typeID);
+
+
+    if (nFail_)
+    {
+        Info<< nl << "        #### "
+            << "Failed in " << nFail_ << " tests "
+            << "out of total " << nTest_ << " tests "
+            << "####\n" << endl;
+        return 1;
+    }
+
+    Info<< nl << "        #### Passed all " << nTest_ <<" tests ####\n" << endl;
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/matrices/DiagonalMatrix/DiagonalMatrix.C b/src/OpenFOAM/matrices/DiagonalMatrix/DiagonalMatrix.C
index 26d92fba2ffcfc05071aafc29e56f0995d7a1e86..1d5146b4b7170daead7531ccc0590112a483706e 100644
--- a/src/OpenFOAM/matrices/DiagonalMatrix/DiagonalMatrix.C
+++ b/src/OpenFOAM/matrices/DiagonalMatrix/DiagonalMatrix.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,14 +28,7 @@ License
 
 #include "DiagonalMatrix.H"
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-template<class Type>
-inline Foam::DiagonalMatrix<Type>::DiagonalMatrix()
-:
-    List<Type>()
-{}
-
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 template<class Type>
 Foam::DiagonalMatrix<Type>::DiagonalMatrix(const label n)
@@ -74,8 +67,10 @@ Foam::DiagonalMatrix<Type>::DiagonalMatrix(const Matrix<Form, Type>& mat)
 }
 
 
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
 template<class Type>
-Foam::DiagonalMatrix<Type>& Foam::DiagonalMatrix<Type>::invert()
+void Foam::DiagonalMatrix<Type>::invert()
 {
     for (Type& val : *this)
     {
@@ -88,13 +83,75 @@ Foam::DiagonalMatrix<Type>& Foam::DiagonalMatrix<Type>::invert()
             val = Type(1)/val;
         }
     }
+}
+
 
-    return this;
+template<class Type>
+template<class CompOp>
+Foam::List<Foam::label> Foam::DiagonalMatrix<Type>::sortPermutation
+(
+    CompOp& compare
+) const
+{
+    List<label> p(this->size());
+    std::iota(p.begin(), p.end(), 0);
+    std::sort
+    (
+        p.begin(),
+        p.end(),
+        [&](label i, label j){ return compare((*this)[i], (*this)[j]); }
+    );
+
+    return p;
+}
+
+
+template<class Type>
+void Foam::DiagonalMatrix<Type>::applyPermutation(const List<label>& p)
+{
+    #ifdef FULLDEBUG
+    if (this->size() != p.size())
+    {
+        FatalErrorInFunction
+            << "Attempt to column-reorder according to an uneven list: " << nl
+            << "DiagonalMatrix diagonal size = " << this->size() << nl
+            << "Permutation list size = " << p.size() << nl
+            << abort(FatalError);
+    }
+    #endif
+
+    List<bool> pass(p.size(), false);
+
+    for (label i = 0; i < p.size(); ++i)
+    {
+        if (pass[i])
+        {
+            continue;
+        }
+        pass[i] = true;
+        label prev = i;
+        label j = p[i];
+        while (i != j)
+        {
+            Swap((*this)[prev], (*this)[j]);
+            pass[j] = true;
+            prev = j;
+            j = p[j];
+        }
+    }
 }
 
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
+
+//- Return the matrix inverse as a DiagonalMatrix if no elem is equal to zero
 template<class Type>
-Foam::DiagonalMatrix<Type> Foam::inv(const DiagonalMatrix<Type>& mat)
+DiagonalMatrix<Type> inv(const DiagonalMatrix<Type>& mat)
 {
     DiagonalMatrix<Type> Ainv(mat.size());
 
@@ -118,4 +175,41 @@ Foam::DiagonalMatrix<Type> Foam::inv(const DiagonalMatrix<Type>& mat)
 }
 
 
+//- Return Matrix column-reordered according to
+//- a given permutation labelList
+template<class Type>
+DiagonalMatrix<Type> applyPermutation
+(
+    const DiagonalMatrix<Type>& mat,
+    const List<label>& p
+)
+{
+    #ifdef FULLDEBUG
+    if (mat.size() != p.size())
+    {
+        FatalErrorInFunction
+            << "Attempt to column-reorder according to an uneven list: " << nl
+            << "DiagonalMatrix diagonal size = " << mat.size() << nl
+            << "Permutation list size = " << p.size() << nl
+            << abort(FatalError);
+    }
+    #endif
+
+    DiagonalMatrix<Type> reordered(mat.size());
+
+    label j = 0;
+    for (const label i : p)
+    {
+        reordered[j] = mat[i];
+        ++j;
+    }
+
+    return reordered;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
 // ************************************************************************* //
diff --git a/src/OpenFOAM/matrices/DiagonalMatrix/DiagonalMatrix.H b/src/OpenFOAM/matrices/DiagonalMatrix/DiagonalMatrix.H
index b8e29d8270692b4fd1fd1333e02fd27a6e8035af..e08800bd77f8101b4bc59fd02af7cf4e87182ac6 100644
--- a/src/OpenFOAM/matrices/DiagonalMatrix/DiagonalMatrix.H
+++ b/src/OpenFOAM/matrices/DiagonalMatrix/DiagonalMatrix.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,7 +28,11 @@ Class
     Foam::DiagonalMatrix
 
 Description
-    A 2D diagonal matrix of objects of type \<Type\>, size (N x N)
+    A templated (N x N) diagonal matrix of objects of \<Type\>, effectively
+    containing N elements, derived from List.
+
+See also
+    Test-DiagonalMatrix.C
 
 SourceFiles
     DiagonalMatrix.C
@@ -39,6 +43,7 @@ SourceFiles
 #define DiagonalMatrix_H
 
 #include "List.H"
+#include <numeric>
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -59,19 +64,27 @@ class DiagonalMatrix
 {
 public:
 
-    // Constructors
+    // Generated Methods
+
+        //- Default construct
+        DiagonalMatrix() = default;
+
+        //- Copy construct
+        DiagonalMatrix(const DiagonalMatrix&) = default;
+
+        //- Copy assignment
+        DiagonalMatrix& operator=(const DiagonalMatrix&) = default;
+
 
-        //- Construct null.
-        DiagonalMatrix<Type>();
+    // Constructors
 
         //- Construct empty from size
         explicit DiagonalMatrix<Type>(const label n);
 
-        //- Construct from size
-        //- initializing all elements to the given value
+        //- Construct from size and initialise all elems to zero
         DiagonalMatrix<Type>(const label n, const zero);
 
-        //- Construct from size and a value
+        //- Construct from size and initialise all elems to value
         DiagonalMatrix<Type>(const label n, const Type& val);
 
         //- Construct from the diagonal of a Matrix
@@ -81,17 +94,18 @@ public:
 
     // Member Functions
 
-        //- Invert the diagonal matrix and return itself
-        DiagonalMatrix<Type>& invert();
-
-};
-
+        //- Return the matrix inverse into itself if no elem is equal to zero
+        void invert();
 
-// Global functions
+        //- Return a sort permutation labelList according to
+        //- a given comparison on the diagonal entries
+        template<class CompOp>
+        List<label> sortPermutation(CompOp& compare) const;
 
-//- Return the diagonal Matrix inverse
-template<class Type>
-DiagonalMatrix<Type> inv(const DiagonalMatrix<Type>& mat);
+        //- Column-reorder this Matrix according to
+        //- a given permutation labelList
+        void applyPermutation(const List<label>& p);
+};
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/OpenFOAM/matrices/Matrix/Matrix.C b/src/OpenFOAM/matrices/Matrix/Matrix.C
index b5ea2e4519d84f1b3cc700ab9c836ffd28cea19a..03beb2c5026b595c15d52f05f4423d728f701ec5 100644
--- a/src/OpenFOAM/matrices/Matrix/Matrix.C
+++ b/src/OpenFOAM/matrices/Matrix/Matrix.C
@@ -644,10 +644,16 @@ void Foam::Matrix<Form, Type>::operator/=(const Type& s)
 }
 
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
 // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * * //
 
+//- Find max value in Matrix
 template<class Form, class Type>
-const Type& Foam::max(const Matrix<Form, Type>& mat)
+const Type& max(const Matrix<Form, Type>& mat)
 {
     if (mat.empty())
     {
@@ -659,8 +665,9 @@ const Type& Foam::max(const Matrix<Form, Type>& mat)
 }
 
 
+//- Find min value in Matrix
 template<class Form, class Type>
-const Type& Foam::min(const Matrix<Form, Type>& mat)
+const Type& min(const Matrix<Form, Type>& mat)
 {
     if (mat.empty())
     {
@@ -672,8 +679,9 @@ const Type& Foam::min(const Matrix<Form, Type>& mat)
 }
 
 
+//- Find the min/max values of Matrix
 template<class Form, class Type>
-Foam::MinMax<Type> Foam::minMax(const Matrix<Form, Type>& mat)
+MinMax<Type> minMax(const Matrix<Form, Type>& mat)
 {
     MinMax<Type> result;
 
@@ -686,10 +694,12 @@ Foam::MinMax<Type> Foam::minMax(const Matrix<Form, Type>& mat)
 }
 
 
+
 // * * * * * * * * * * * * * * * Global Operators  * * * * * * * * * * * * * //
 
+//- Matrix negation
 template<class Form, class Type>
-Form Foam::operator-(const Matrix<Form, Type>& mat)
+Form operator-(const Matrix<Form, Type>& mat)
 {
     Form result(mat.sizes());
 
@@ -705,8 +715,9 @@ Form Foam::operator-(const Matrix<Form, Type>& mat)
 }
 
 
+//- Matrix addition. Returns Matrix of the same form as the first parameter.
 template<class Form1, class Form2, class Type>
-Form1 Foam::operator+
+Form1 operator+
 (
     const Matrix<Form1, Type>& A,
     const Matrix<Form2, Type>& B
@@ -738,8 +749,9 @@ Form1 Foam::operator+
 }
 
 
+//- Matrix subtraction. Returns Matrix of the same form as the first parameter.
 template<class Form1, class Form2, class Type>
-Form1 Foam::operator-
+Form1 operator-
 (
     const Matrix<Form1, Type>& A,
     const Matrix<Form2, Type>& B
@@ -771,8 +783,9 @@ Form1 Foam::operator-
 }
 
 
+//- Scalar multiplication of Matrix
 template<class Form, class Type>
-Form Foam::operator*(const Type& s, const Matrix<Form, Type>& mat)
+Form operator*(const Type& s, const Matrix<Form, Type>& mat)
 {
     Form result(mat.sizes());
 
@@ -788,8 +801,17 @@ Form Foam::operator*(const Type& s, const Matrix<Form, Type>& mat)
 }
 
 
+//- Scalar multiplication of Matrix
 template<class Form, class Type>
-Form Foam::operator+(const Type& s, const Matrix<Form, Type>& mat)
+Form operator*(const Matrix<Form, Type>& mat, const Type& s)
+{
+    return s*mat;
+}
+
+
+//- Scalar addition of Matrix
+template<class Form, class Type>
+Form operator+(const Type& s, const Matrix<Form, Type>& mat)
 {
     Form result(mat.sizes());
 
@@ -805,8 +827,17 @@ Form Foam::operator+(const Type& s, const Matrix<Form, Type>& mat)
 }
 
 
+//- Scalar addition of Matrix
+template<class Form, class Type>
+Form operator+(const Matrix<Form, Type>& mat, const Type& s)
+{
+    return s + mat;
+}
+
+
+//- Scalar subtraction of Matrix
 template<class Form, class Type>
-Form Foam::operator-(const Type& s, const Matrix<Form, Type>& mat)
+Form operator-(const Type& s, const Matrix<Form, Type>& mat)
 {
     Form result(mat.sizes());
 
@@ -822,22 +853,9 @@ Form Foam::operator-(const Type& s, const Matrix<Form, Type>& mat)
 }
 
 
+//- Scalar subtraction of Matrix
 template<class Form, class Type>
-Form Foam::operator*(const Matrix<Form, Type>& mat, const Type& s)
-{
-    return s*mat;
-}
-
-
-template<class Form, class Type>
-Form Foam::operator+(const Matrix<Form, Type>& mat, const Type& s)
-{
-    return s + mat;
-}
-
-
-template<class Form, class Type>
-Form Foam::operator-(const Matrix<Form, Type>& mat, const Type& s)
+Form operator-(const Matrix<Form, Type>& mat, const Type& s)
 {
     Form result(mat.sizes());
 
@@ -853,8 +871,9 @@ Form Foam::operator-(const Matrix<Form, Type>& mat, const Type& s)
 }
 
 
+//- Scalar division of Matrix
 template<class Form, class Type>
-Form Foam::operator/(const Matrix<Form, Type>& mat, const Type& s)
+Form operator/(const Matrix<Form, Type>& mat, const Type& s)
 {
     Form result(mat.sizes());
 
@@ -870,9 +889,10 @@ Form Foam::operator/(const Matrix<Form, Type>& mat, const Type& s)
 }
 
 
+//- Matrix-Matrix multiplication using ikj-algorithm
 template<class Form1, class Form2, class Type>
-typename Foam::typeOfInnerProduct<Type, Form1, Form2>::type
-Foam::operator*
+typename typeOfInnerProduct<Type, Form1, Form2>::type
+operator*
 (
     const Matrix<Form1, Type>& A,
     const Matrix<Form2, Type>& B
@@ -912,9 +932,10 @@ Foam::operator*
 }
 
 
+//- Implicit inner product of Matrix-Matrix, equivalent to A.T()*B
 template<class Form1, class Form2, class Type>
-typename Foam::typeOfInnerProduct<Type, Form1, Form2>::type
-Foam::operator&
+typename typeOfInnerProduct<Type, Form1, Form2>::type
+operator&
 (
     const Matrix<Form1, Type>& AT,
     const Matrix<Form2, Type>& B
@@ -954,9 +975,10 @@ Foam::operator&
 }
 
 
+//- Implicit outer product of Matrix-Matrix, equivalent to A*B.T()
 template<class Form1, class Form2, class Type>
-typename Foam::typeOfInnerProduct<Type, Form1, Form2>::type
-Foam::operator^
+typename typeOfInnerProduct<Type, Form1, Form2>::type
+operator^
 (
     const Matrix<Form1, Type>& A,
     const Matrix<Form2, Type>& BT
@@ -996,7 +1018,11 @@ Foam::operator^
 }
 
 
-// * * * * * * * * * * * * * * * *  IOStream operators * * * * * * * * * * * //
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * IOStream operators  * * * * * * * * * * * * * //
 
 #include "MatrixIO.C"
 
diff --git a/src/OpenFOAM/matrices/Matrix/Matrix.H b/src/OpenFOAM/matrices/Matrix/Matrix.H
index bb66c5e5b7134c8959b1a1d6436ff9e939f1d4a9..673258a7c737baa135dc42f04cc02a74c008410f 100644
--- a/src/OpenFOAM/matrices/Matrix/Matrix.H
+++ b/src/OpenFOAM/matrices/Matrix/Matrix.H
@@ -220,7 +220,6 @@ public:
         //  Subscript checking only with FULLDEBUG
         inline Type& at(const label idx);
 
-
     // Block Access (const)
 
         //- Return const column or column's subset of Matrix
@@ -265,7 +264,6 @@ public:
             const label colIndex
         ) const;
 
-
     // Block Access (non-const)
 
         //- Return column or column's subset of Matrix
@@ -301,7 +299,6 @@ public:
             const label colIndex
         );
 
-
     // Check
 
         //- Check index i is within valid range [0, m)
@@ -316,7 +313,6 @@ public:
         //- True if all entries have identical values, and Matrix is non-empty
         inline bool uniform() const;
 
-
     // Edit
 
         //- Clear Matrix, i.e. set sizes to zero
@@ -342,10 +338,9 @@ public:
         //- Resize Matrix without reallocating storage (unsafe)
         inline void shallowResize(const label m, const label n);
 
-        //- Round to zero elements with magnitude smaller than tol (SMALL)
+        //- Round elements with magnitude smaller than tol (SMALL) to zero
         void round(const scalar tol = SMALL);
 
-
     // Operations
 
         //- Return (conjugate) transpose of Matrix
@@ -386,7 +381,6 @@ public:
 
         //- Return Frobenius norm of Matrix
         //  Optional without sqrt for parallel usage.
-        //  https://en.wikipedia.org/wiki/Matrix_norm#Frobenius_norm
         scalar norm(const bool noSqrt=false) const;
 
 
@@ -596,159 +590,6 @@ template<class Form, class Type>
 Ostream& operator<<(Ostream& os, const Matrix<Form, Type>& mat);
 
 
-// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * * //
-
-//- Find max value in Matrix
-template<class Form, class Type>
-const Type& max(const Matrix<Form, Type>& mat);
-
-//- Find min value in Matrix
-template<class Form, class Type>
-const Type& min(const Matrix<Form, Type>& mat);
-
-//- Find the min/max values of Matrix
-template<class Form, class Type>
-MinMax<Type> minMax(const Matrix<Form, Type>& mat);
-
-
-// * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * * //
-
-//- Matrix negation
-template<class Form, class Type>
-Form operator-(const Matrix<Form, Type>& mat);
-
-//- Matrix addition. Returns Matrix of the same form as the first parameter.
-template<class Form1, class Form2, class Type>
-Form1 operator+
-(
-    const Matrix<Form1, Type>& A,
-    const Matrix<Form2, Type>& B
-);
-
-//- Matrix subtraction. Returns Matrix of the same form as the first parameter.
-template<class Form1, class Form2, class Type>
-Form1 operator-
-(
-    const Matrix<Form1, Type>& A,
-    const Matrix<Form2, Type>& B
-);
-
-//- Scalar multiplication of Matrix
-template<class Form, class Type>
-Form operator*
-(
-    const Type& s,
-    const Matrix<Form, Type>& mat
-);
-
-//- Scalar addition of Matrix
-template<class Form, class Type>
-Form operator+
-(
-    const Type& s,
-    const Matrix<Form, Type>& mat
-);
-
-//- Scalar subtraction of Matrix
-template<class Form, class Type>
-Form operator-
-(
-    const Type& s,
-    const Matrix<Form, Type>& mat
-);
-
-//- Scalar multiplication of Matrix
-template<class Form, class Type>
-Form operator*
-(
-    const Matrix<Form, Type>& mat,
-    const Type& s
-);
-
-//- Scalar addition of Matrix
-template<class Form, class Type>
-Form operator+
-(
-    const Matrix<Form, Type>& mat,
-    const Type& s
-);
-
-//- Scalar subtraction of Matrix
-template<class Form, class Type>
-Form operator-
-(
-    const Matrix<Form, Type>& mat,
-    const Type& s
-);
-
-//- Scalar division of Matrix
-template<class Form, class Type>
-Form operator/
-(
-    const Matrix<Form, Type>& mat,
-    const Type& s
-);
-
-//- Matrix-Matrix multiplication using ikj-algorithm
-template<class Form1, class Form2, class Type>
-typename typeOfInnerProduct<Type, Form1, Form2>::type
-operator*
-(
-    const Matrix<Form1, Type>& A,
-    const Matrix<Form2, Type>& B
-);
-
-//- Matrix-vector multiplication (A * x), where x is a column vector
-template<class Form, class Type>
-inline tmp<Field<Type>> operator*
-(
-    const Matrix<Form, Type>& mat,
-    const UList<Type>& x
-);
-
-//- Matrix-vector multiplication (A * x), where x is a column vector
-template<class Form, class Type, class Addr>
-inline tmp<Field<Type>> operator*
-(
-    const Matrix<Form, Type>& mat,
-    const IndirectListBase<Type, Addr>& x
-);
-
-//- Vector-Matrix multiplication (x * A), where x is a row vector
-template<class Form, class Type>
-inline tmp<Field<Type>> operator*
-(
-    const UList<Type>& x,
-    const Matrix<Form, Type>& mat
-);
-
-//- Vector-Matrix multiplication (x * A), where x is a row vector
-template<class Form, class Type, class Addr>
-inline tmp<Field<Type>> operator*
-(
-    const IndirectListBase<Type, Addr>& x,
-    const Matrix<Form, Type>& mat
-);
-
-//- Implicit inner product of Matrix-Matrix, equivalent to A.T()*B
-template<class Form1, class Form2, class Type>
-typename typeOfInnerProduct<Type, Form1, Form2>::type
-operator&
-(
-    const Matrix<Form1, Type>& ATranspose,
-    const Matrix<Form2, Type>& B
-);
-
-//- Implicit outer product of Matrix-Matrix, equivalent to A*B.T()
-template<class Form1, class Form2, class Type>
-typename typeOfInnerProduct<Type, Form1, Form2>::type
-operator^
-(
-    const Matrix<Form1, Type>& A,
-    const Matrix<Form2, Type>& BTranspose
-);
-
-
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 } // End namespace Foam
diff --git a/src/OpenFOAM/matrices/Matrix/MatrixI.H b/src/OpenFOAM/matrices/Matrix/MatrixI.H
index 435b22b7c5c07e42ce264b963c7788c355427d2b..ab2909a6738cfd8e22602f9df24b162ca76cda54 100644
--- a/src/OpenFOAM/matrices/Matrix/MatrixI.H
+++ b/src/OpenFOAM/matrices/Matrix/MatrixI.H
@@ -242,7 +242,7 @@ inline const Type& Foam::Matrix<Form, Type>::at(const label idx) const
             << abort(FatalError);
     }
     #endif
-    return (v_ + idx);
+    return *(v_ + idx);
 }
 
 
@@ -257,7 +257,7 @@ inline Type& Foam::Matrix<Form, Type>::at(const label idx)
             << abort(FatalError);
     }
     #endif
-    return (v_ + idx);
+    return *(v_ + idx);
 }
 
 
@@ -608,8 +608,16 @@ inline Type* Foam::Matrix<Form, Type>::operator[](const label irow)
 }
 
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * Global Operators  * * * * * * * * * * * * * //
+
+//- Matrix-vector multiplication (A * x), where x is a column vector
 template<class Form, class Type>
-inline Foam::tmp<Foam::Field<Type>> Foam::operator*
+inline tmp<Field<Type>> operator*
 (
     const Matrix<Form, Type>& mat,
     const UList<Type>& x
@@ -619,8 +627,9 @@ inline Foam::tmp<Foam::Field<Type>> Foam::operator*
 }
 
 
+//- Matrix-vector multiplication (A * x), where x is a column vector
 template<class Form, class Type, class Addr>
-inline Foam::tmp<Foam::Field<Type>> Foam::operator*
+inline tmp<Field<Type>> operator*
 (
     const Matrix<Form, Type>& mat,
     const IndirectListBase<Type, Addr>& x
@@ -630,8 +639,9 @@ inline Foam::tmp<Foam::Field<Type>> Foam::operator*
 }
 
 
+//- Vector-Matrix multiplication (x * A), where x is a row vector
 template<class Form, class Type>
-inline Foam::tmp<Foam::Field<Type>> Foam::operator*
+inline tmp<Field<Type>> operator*
 (
     const UList<Type>& x,
     const Matrix<Form, Type>& mat
@@ -641,8 +651,9 @@ inline Foam::tmp<Foam::Field<Type>> Foam::operator*
 }
 
 
+//- Vector-Matrix multiplication (x * A), where x is a row vector
 template<class Form, class Type, class Addr>
-inline Foam::tmp<Foam::Field<Type>> Foam::operator*
+inline tmp<Field<Type>> operator*
 (
     const IndirectListBase<Type, Addr>& x,
     const Matrix<Form, Type>& mat
@@ -651,5 +662,8 @@ inline Foam::tmp<Foam::Field<Type>> Foam::operator*
     return mat.Tmul(x);
 }
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
 
 // ************************************************************************* //
diff --git a/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.C b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.C
index 7b6ab90153ffb581eec6d94c7fbc15688ad409da..54b88b39ae7ce7ac36b7a178e08846992ac15433 100644
--- a/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.C
+++ b/src/OpenFOAM/matrices/MatrixBlock/MatrixBlock.C
@@ -176,7 +176,7 @@ void Foam::MatrixBlock<MatrixType>::operator=
     const ConstMatrixBlock<MatrixType>& Mb
 )
 {
-    if (this != &Mb)
+    if (reinterpret_cast<const ConstMatrixBlock<MatrixType>*>(this) != &Mb)
     {
         if (mRows_ != Mb.m() || nCols_ != Mb.n())
         {
@@ -233,7 +233,7 @@ void Foam::MatrixBlock<MatrixType>::operator=
     const ConstMatrixBlock<MatrixType2>& Mb
 )
 {
-    if (this != &Mb)
+    if (reinterpret_cast<const ConstMatrixBlock<MatrixType2>*>(this) != &Mb)
     {
         if (mRows_ != Mb.m() || nCols_ != Mb.n())
         {
diff --git a/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrix.H b/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrix.H
index 5b09ea7568b0e153706f494c4b40122a2a4b2843..b5394f017aa69929b9562bbdedeae619b81cbd79 100644
--- a/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrix.H
+++ b/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrix.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,13 +28,14 @@ Class
     Foam::RectangularMatrix
 
 Description
-    A templated 2D rectangular m x n matrix of objects of \<Type\>.
+    A templated (M x N) rectangular matrix of objects of \<Type\>,
+    containing M*N elements, derived from Matrix.
 
-    The matrix dimensions are used for subscript bounds checking etc.
+See also
+    Test-RectangularMatrix.C
 
 SourceFiles
     RectangularMatrixI.H
-    RectangularMatrix.C
 
 \*---------------------------------------------------------------------------*/
 
@@ -61,10 +62,19 @@ class RectangularMatrix
 
 public:
 
-    // Constructors
+    // Generated Methods
+
+        //- Default construct
+        RectangularMatrix() = default;
+
+        //- Copy construct
+        RectangularMatrix(const RectangularMatrix&) = default;
+
+        //- Copy assignment
+        RectangularMatrix& operator=(const RectangularMatrix&) = default;
+
 
-        //- Construct null
-        inline RectangularMatrix();
+    // Constructors
 
         //- Construct a square matrix (rows == columns)
         inline explicit RectangularMatrix(const label n);
@@ -85,15 +95,15 @@ public:
         template<class AnyType>
         inline RectangularMatrix(const labelPair& dims, const Identity<AnyType>);
 
-        //- Construct given number of rows/columns
+        //- Construct given number of rows/columns by using a label pair
         inline explicit RectangularMatrix(const labelPair& dims);
 
-        //- Construct given number of rows/columns
-        //- initializing all elements to zero
+        //- Construct given number of rows/columns by using a label pair
+        //- and initializing all elements to zero
         inline RectangularMatrix(const labelPair& dims, const zero);
 
-        //- Construct given number of rows/columns
-        //- initializing all elements to the given value
+        //- Construct given number of rows/columns by using a label pair
+        //- and initializing all elements to the given value
         inline RectangularMatrix(const labelPair& dims, const Type& val);
 
         //- Construct from a block of another matrix
@@ -107,7 +117,7 @@ public:
         //- Construct as copy of a square matrix
         inline RectangularMatrix(const SquareMatrix<Type>& mat);
 
-        //- Construct from Istream.
+        //- Construct from Istream
         inline explicit RectangularMatrix(Istream& is);
 
         //- Clone
@@ -124,41 +134,6 @@ public:
 };
 
 
-// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
-
-template<class Type>
-class typeOfInnerProduct<Type, RectangularMatrix<Type>, RectangularMatrix<Type>>
-{
-public:
-
-    typedef RectangularMatrix<Type> type;
-};
-
-
-template<class Type>
-class typeOfInnerProduct<Type, RectangularMatrix<Type>, SquareMatrix<Type>>
-{
-public:
-
-    typedef RectangularMatrix<Type> type;
-};
-
-
-template<class Type>
-class typeOfInnerProduct<Type, SquareMatrix<Type>, RectangularMatrix<Type>>
-{
-public:
-
-    typedef RectangularMatrix<Type> type;
-};
-
-
-// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
-
-template<class Type>
-RectangularMatrix<Type> outer(const Field<Type>& f1, const Field<Type>& f2);
-
-
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 } // End namespace Foam
diff --git a/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrixI.H b/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrixI.H
index 7cef3593e77c223e6e24c17022a14b6797ab9374..9b98e72caaa5fcee6b1dcfee4595abf711a89a36 100644
--- a/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrixI.H
+++ b/src/OpenFOAM/matrices/RectangularMatrix/RectangularMatrixI.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,13 +28,6 @@ License
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-template<class Type>
-inline Foam::RectangularMatrix<Type>::RectangularMatrix()
-:
-    Matrix<RectangularMatrix<Type>, Type>()
-{}
-
-
 template<class Type>
 inline Foam::RectangularMatrix<Type>::RectangularMatrix
 (
@@ -197,8 +190,38 @@ inline void Foam::RectangularMatrix<Type>::operator=(const Type& val)
 namespace Foam
 {
 
+// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
+
+template<class Type>
+class typeOfInnerProduct<Type, RectangularMatrix<Type>, RectangularMatrix<Type>>
+{
+public:
+
+    typedef RectangularMatrix<Type> type;
+};
+
+
+template<class Type>
+class typeOfInnerProduct<Type, RectangularMatrix<Type>, SquareMatrix<Type>>
+{
+public:
+
+    typedef RectangularMatrix<Type> type;
+};
+
+
+template<class Type>
+class typeOfInnerProduct<Type, SquareMatrix<Type>, RectangularMatrix<Type>>
+{
+public:
+
+    typedef RectangularMatrix<Type> type;
+};
+
+
 // * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
 
+// Return the outer product of Field-Field as RectangularMatrix
 template<class Type>
 inline Foam::RectangularMatrix<Type> outer
 (
@@ -224,5 +247,4 @@ inline Foam::RectangularMatrix<Type> outer
 
 } // End namespace Foam
 
-
 // ************************************************************************* //
diff --git a/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.C b/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.C
index 4bc1f0f78f6be55b324467e0ea42e17bd941f885..1506cb997236626c4341d5ccaeb6e27bec5ffa95 100644
--- a/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.C
+++ b/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2013-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -30,10 +30,80 @@ License
 #include "RectangularMatrix.H"
 #include "labelList.H"
 
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class Type>
+template<class CompOp>
+Foam::List<Foam::label> Foam::SquareMatrix<Type>::sortPermutation
+(
+    CompOp& compare
+) const
+{
+    List<label> p(this->m());
+    std::iota(p.begin(), p.end(), 0);
+    std::sort
+    (
+        p.begin(),
+        p.end(),
+        [&](label i, label j){ return compare((*this)(i,i), (*this)(j,j)); }
+    );
+
+    return p;
+}
+
+
+template<class Type>
+void Foam::SquareMatrix<Type>::applyPermutation(const List<label>& p)
+{
+    #ifdef FULLDEBUG
+    if (this->m() != p.size())
+    {
+        FatalErrorInFunction
+            << "Attempt to column-reorder according to an uneven list: " << nl
+            << "SquareMatrix diagonal size = " << this->m() << nl
+            << "Permutation list size = " << p.size() << nl
+            << abort(FatalError);
+    }
+    #endif
+
+    SquareMatrix<Type> reordered(this->sizes());
+
+    label j = 0;
+    for (const label i : p)
+    {
+        reordered.subColumn(j) = this->subColumn(i);
+        ++j;
+    }
+
+    this->transfer(reordered);
+}
+
+
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+template<class Type>
+template<class AnyType>
+void Foam::SquareMatrix<Type>::operator=(const Identity<AnyType>)
+{
+    Matrix<SquareMatrix<Type>, Type>::operator=(Zero);
+
+    for (label i = 0; i < this->n(); ++i)
+    {
+        this->operator()(i, i) = pTraits<Type>::one;
+    }
+}
+
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+namespace Foam
+{
+
+// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
+
+//- Return the determinant of the LU decomposed SquareMatrix
 template<class Type>
-Foam::scalar Foam::detDecomposed
+scalar detDecomposed
 (
     const SquareMatrix<Type>& matrix,
     const label sign
@@ -50,8 +120,9 @@ Foam::scalar Foam::detDecomposed
 }
 
 
+//- Return the determinant of SquareMatrix
 template<class Type>
-Foam::scalar Foam::det(const SquareMatrix<Type>& matrix)
+scalar det(const SquareMatrix<Type>& matrix)
 {
     SquareMatrix<Type> matrixTmp = matrix;
 
@@ -63,8 +134,9 @@ Foam::scalar Foam::det(const SquareMatrix<Type>& matrix)
 }
 
 
+//- Return the SquareMatrix det and the LU decomposition in the original matrix
 template<class Type>
-Foam::scalar Foam::det(SquareMatrix<Type>& matrix)
+scalar det(SquareMatrix<Type>& matrix)
 {
     labelList pivotIndices(matrix.m());
     label sign;
@@ -74,19 +146,52 @@ Foam::scalar Foam::det(SquareMatrix<Type>& matrix)
 }
 
 
-// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
-
+//- Return Matrix column-reordered according to
+//- a given permutation labelList
 template<class Type>
-template<class AnyType>
-void Foam::SquareMatrix<Type>::operator=(const Identity<AnyType>)
+SquareMatrix<Type> applyPermutation
+(
+    const SquareMatrix<Type>& mat,
+    const List<label>& p
+)
 {
-    Matrix<SquareMatrix<Type>, Type>::operator=(Zero);
+    #ifdef FULLDEBUG
+    if (mat.m() != p.size())
+    {
+        FatalErrorInFunction
+            << "Attempt to column-reorder according to an uneven list: " << nl
+            << "SquareMatrix diagonal size = " << mat.m() << nl
+            << "Permutation list size = " << p.size() << nl
+            << abort(FatalError);
+    }
+    #endif
 
-    for (label i=0; i < this->n(); ++i)
+    SquareMatrix<Type> reordered(mat.sizes());
+
+    label j = 0;
+    for (const label i : p)
     {
-        this->operator()(i, i) = pTraits<Type>::one;
+        reordered.subColumn(j) = mat.subColumn(i);
+        ++j;
     }
+
+    return reordered;
 }
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+class typeOfInnerProduct<Type, SquareMatrix<Type>, SquareMatrix<Type>>
+{
+public:
+
+    typedef SquareMatrix<Type> type;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.H b/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.H
index e404910e069a8e4fad048a10d2056e064fcd4ed8..a79f2d9f4230d6a8335adfb5390c6a2610be9ddb 100644
--- a/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.H
+++ b/src/OpenFOAM/matrices/SquareMatrix/SquareMatrix.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,8 +28,11 @@ Class
     Foam::SquareMatrix
 
 Description
-    A templated 2D square matrix of objects of \<T\>, where the n x n matrix
-    dimension is known and used for subscript bounds checking, etc.
+    A templated (N x N) square matrix of objects of \<Type\>,
+    containing N*N elements, derived from Matrix.
+
+See also
+    Test-SquareMatrix.C
 
 SourceFiles
     SquareMatrixI.H
@@ -42,6 +45,7 @@ SourceFiles
 
 #include "Matrix.H"
 #include "Identity.H"
+#include <numeric>
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -64,10 +68,19 @@ class SquareMatrix
 
 public:
 
-    // Constructors
+    // Generated Methods
+
+        //- Default construct
+        SquareMatrix() = default;
+
+        //- Copy construct
+        SquareMatrix(const SquareMatrix&) = default;
 
-        //- Construct null
-        inline SquareMatrix();
+        //- Copy assignment
+        SquareMatrix& operator=(const SquareMatrix&) = default;
+
+
+    // Constructors
 
         //- Construct for given size (rows == cols)
         inline explicit SquareMatrix(const label n);
@@ -85,20 +98,25 @@ public:
         template<class AnyType>
         inline SquareMatrix(const label n, const Identity<AnyType>);
 
+        //- Construct for given size (rows == cols) by using a labelPair
+        //- initializing to the identity matrix
         template<class AnyType>
         inline SquareMatrix(const labelPair& dims, const Identity<AnyType>);
 
-        //- Construct given number of rows/columns (checked to be equal)
+        //- Construct given number of rows/columns
+        //- by using a labelPair (checked to be equal)
         //  For constructor consistency in rectangular matrices
         inline explicit SquareMatrix(const labelPair& dims);
 
-        //- Construct given number of rows/columns (checked to be equal)
-        //- initializing all elements to zero
+        //- Construct given number of rows/columns
+        //- by using a labelPair (checked to be equal)
+        //- and initializing all elements to zero
         //  For constructor consistency with rectangular matrices
         inline SquareMatrix(const labelPair& dims, const zero);
 
-        //- Construct given number of rows/columns (checked to be equal)
-        //- initializing all elements to the given value
+        //- Construct given number of rows/columns
+        //- by using a labelPair (checked to be equal)
+        //- and initializing all elements to the given value
         //  For constructor consistency with rectangular matrices
         inline SquareMatrix(const labelPair& dims, const Type& val);
 
@@ -106,7 +124,7 @@ public:
         //- initializing all elements to zero
         inline SquareMatrix(const label m, const label n, const zero);
 
-        //- Construct from sub-matrix block
+        //- Construct from const sub-matrix block
         template<class MatrixType>
         inline SquareMatrix(const ConstMatrixBlock<MatrixType>& mat);
 
@@ -149,6 +167,17 @@ public:
         //- Return true if the square matrix is reduced tridiagonal
         inline bool tridiagonal() const;
 
+    // Sort
+
+        //- Return a sort permutation labelList according to
+        //- a given comparison on the diagonal entries
+        template<class CompOp>
+        List<label> sortPermutation(CompOp& compare) const;
+
+        //- Column-reorder this Matrix according to
+        //- a given permutation labelList
+        void applyPermutation(const List<label>& p);
+
 
     // Member Operators
 
@@ -164,28 +193,6 @@ public:
 };
 
 
-// * * * * * * * * * * * * * * * Global Functions  * * * * * * * * * * * * * //
-
-//- Return the LU decomposed SquareMatrix det
-template<class Type>
-scalar detDecomposed(const SquareMatrix<Type>&, const label sign);
-
-//- Return the SquareMatrix det
-template<class Type>
-scalar det(const SquareMatrix<Type>&);
-
-//- Return the SquareMatrix det and the LU decomposition in the original matrix
-template<class Type>
-scalar det(SquareMatrix<Type>&);
-
-template<class Type>
-class typeOfInnerProduct<Type, SquareMatrix<Type>, SquareMatrix<Type>>
-{
-public:
-
-    typedef SquareMatrix<Type> type;
-};
-
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 } // End namespace Foam
diff --git a/src/OpenFOAM/matrices/SquareMatrix/SquareMatrixI.H b/src/OpenFOAM/matrices/SquareMatrix/SquareMatrixI.H
index 75e893e068f8c9d91e32d83aaec652364b967455..61933881e1139aced6e9e74a8caa7403e29f917c 100644
--- a/src/OpenFOAM/matrices/SquareMatrix/SquareMatrixI.H
+++ b/src/OpenFOAM/matrices/SquareMatrix/SquareMatrixI.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -37,13 +37,6 @@ License
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-template<class Type>
-inline Foam::SquareMatrix<Type>::SquareMatrix()
-:
-    Matrix<SquareMatrix<Type>, Type>()
-{}
-
-
 template<class Type>
 inline Foam::SquareMatrix<Type>::SquareMatrix(const label n)
 :
@@ -83,7 +76,7 @@ inline Foam::SquareMatrix<Type>::SquareMatrix
 :
     Matrix<SquareMatrix<Type>, Type>(n, n, Zero)
 {
-    for (label i=0; i < n; ++i)
+    for (label i = 0; i < n; ++i)
     {
         this->operator()(i, i) = pTraits<Type>::one;
     }
@@ -318,6 +311,7 @@ namespace Foam
 
 // * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
 
+// Return the outer product of Field-Field as SquareMatrix
 template<class Type>
 inline Foam::SquareMatrix<Type> symmOuter
 (
diff --git a/src/OpenFOAM/matrices/SymmetricSquareMatrix/SymmetricSquareMatrix.C b/src/OpenFOAM/matrices/SymmetricSquareMatrix/SymmetricSquareMatrix.C
index de6291e361b6e09160ff5ca3c7305e66238c3ef3..b50a96e7b1b3f009c60147cc15d4d8a99b6a8e30 100644
--- a/src/OpenFOAM/matrices/SymmetricSquareMatrix/SymmetricSquareMatrix.C
+++ b/src/OpenFOAM/matrices/SymmetricSquareMatrix/SymmetricSquareMatrix.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -126,4 +126,4 @@ void Foam::SymmetricSquareMatrix<Type>::operator=(const Identity<AnyType>)
 }
 
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// ************************************************************************* //
diff --git a/src/OpenFOAM/matrices/SymmetricSquareMatrix/SymmetricSquareMatrix.H b/src/OpenFOAM/matrices/SymmetricSquareMatrix/SymmetricSquareMatrix.H
index 49af9fae42f1c897b9aed10cec78ab2919cd4d97..c04ec0c8559f1a6677847b5d5006b5609afe3ed5 100644
--- a/src/OpenFOAM/matrices/SymmetricSquareMatrix/SymmetricSquareMatrix.H
+++ b/src/OpenFOAM/matrices/SymmetricSquareMatrix/SymmetricSquareMatrix.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,8 +28,11 @@ Class
     Foam::SymmetricSquareMatrix
 
 Description
-    A templated 2D square symmetric matrix of objects of \<T\>, where the
-    n x n matrix dimension is known and used for subscript bounds checking, etc.
+    A templated (N x N) square matrix of objects of \<Type\>,
+    containing N*N elements, derived from Matrix.
+
+See also
+    Test-SymmetricSquareMatrix.C
 
 SourceFiles
     SymmetricSquareMatrixI.H
@@ -59,10 +62,19 @@ class SymmetricSquareMatrix
 
 public:
 
-    // Constructors
+    // Generated Methods
+
+        //- Default construct
+        SymmetricSquareMatrix() = default;
+
+        //- Copy construct
+        SymmetricSquareMatrix(const SymmetricSquareMatrix&) = default;
 
-        //- Construct null
-        inline SymmetricSquareMatrix();
+        //- Copy assignment
+        SymmetricSquareMatrix& operator=(const SymmetricSquareMatrix&) = default;
+
+
+    // Constructors
 
         //- Construct for given size (rows == cols)
         inline explicit SymmetricSquareMatrix(const label n);
@@ -76,7 +88,7 @@ public:
         inline SymmetricSquareMatrix(const label n, const Type& val);
 
         //- Construct for given size (rows == cols)
-        //- setting the diagonal to one and off-diagonals to zero
+        //- initializing to the identity matrix
         template<class AnyType>
         inline SymmetricSquareMatrix(const label n, const Identity<AnyType>);
 
diff --git a/src/OpenFOAM/matrices/SymmetricSquareMatrix/SymmetricSquareMatrixI.H b/src/OpenFOAM/matrices/SymmetricSquareMatrix/SymmetricSquareMatrixI.H
index 79c6b2a05e766529fce29885ff0c56d0ab48279f..31eff6076595dfecab80516349f2e9196614daa6 100644
--- a/src/OpenFOAM/matrices/SymmetricSquareMatrix/SymmetricSquareMatrixI.H
+++ b/src/OpenFOAM/matrices/SymmetricSquareMatrix/SymmetricSquareMatrixI.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -37,13 +37,6 @@ License
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-template<class Type>
-inline Foam::SymmetricSquareMatrix<Type>::SymmetricSquareMatrix()
-:
-    Matrix<SymmetricSquareMatrix<Type>, Type>()
-{}
-
-
 template<class Type>
 inline Foam::SymmetricSquareMatrix<Type>::SymmetricSquareMatrix(const label n)
 :