From bf9d74ba8bf6e6e6ab12bbc600d11be731432685 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Thu, 6 Jun 2019 09:46:31 +0200
Subject: [PATCH] ENH: increase robustness of PrecisionAdaptor

- overload the ref() method to allow modification of the referenced
  (non-const) field directly. Same as constCast(), but less typing
  and less prone to error.

- construct ConstPrecisionAdaptor from tmp for improved efficiency.
---
 .../Field/PrecisionAdaptor/PrecisionAdaptor.H | 103 ++++++++++++++++--
 .../lduMatrix/solvers/GAMG/GAMGSolverSolve.C  |  17 +--
 .../matrices/lduMatrix/solvers/PBiCG/PBiCG.C  |   2 +-
 .../lduMatrix/solvers/PBiCGStab/PBiCGStab.C   |   4 +-
 .../matrices/lduMatrix/solvers/PCG/PCG.C      |   2 +-
 .../solvers/smoothSolver/smoothSolver.C       |   2 +-
 .../faScalarMatrix/faScalarMatrix.C           |   1 -
 .../fvMatrices/fvMatrix/fvMatrixSolve.C       |   4 +-
 .../fvScalarMatrix/fvScalarMatrix.C           |   4 +-
 9 files changed, 107 insertions(+), 32 deletions(-)

diff --git a/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H b/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H
index 80f7dbc464f..0c33ed73886 100644
--- a/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H
+++ b/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H
@@ -49,28 +49,85 @@ class ConstPrecisionAdaptor
 :
     public tmp<Field<Type>>
 {
+    // Private Member Functions
+
+        //- Copy in field
+        void copyInput(const Field<InputType>& input)
+        {
+            this->clear();
+
+            Field<Type>* p = new Field<Type>(input.size());
+            this->reset(p);
+            std::copy(input.cbegin(), input.cend(), p->begin());
+        }
+
+        //- Construct from tmp Field, copy/move as required
+        void moveInput(tmp<Field<InputType>>& input)
+        {
+            if (std::is_same<Type, InputType>::value)
+            {
+                auto& tinput = reinterpret_cast<tmp<FieldType>&>(input);
+
+                if (tinput.isTmp())
+                {
+                    this->clear();
+                    this->swap(tinput);
+                }
+                else
+                {
+                    this->cref(tinput.cref());
+                }
+            }
+            else
+            {
+                this->copyInput(input());
+            }
+            input.clear();
+        }
+
+
 public:
 
+    //- The adapted field type
+    typedef Field<Type> FieldType;
+
+
     // Constructors
 
-        //- Construct from InputType
+        //- Construct from Field<InputType>, copying on input as required
         ConstPrecisionAdaptor(const Field<InputType>& input)
         :
             tmp<Field<Type>>()
         {
             if (std::is_same<Type, InputType>::value)
             {
-                // Set reference - cast for compiler to handle different types
-                this->cref(reinterpret_cast<const Field<Type>&>(input));
+                this->cref(reinterpret_cast<const FieldType&>(input));
             }
             else
             {
-                this->reset(new Field<Type>(input.size()));
-                std::copy(input.cbegin(), input.cend(), this->ref().begin());
+                this->copyInput(input);
             }
         }
 
 
+        //- Construct from tmp Field, copy/move as required
+        ConstPrecisionAdaptor(tmp<Field<InputType>>&& input)
+        :
+            tmp<Field<Type>>()
+        {
+            this->moveInput(input);
+        }
+
+
+        //- Construct from tmp Field, copy/move as required
+        ConstPrecisionAdaptor(const tmp<Field<InputType>>& input)
+        :
+            tmp<Field<Type>>()
+        {
+            this->moveInput(const_cast<tmp<Field<InputType>>&>(input));
+        }
+
+
     // Member Functions
 
         //- Return the field
@@ -82,7 +139,7 @@ public:
         {
             if (std::is_same<Type, InputType>::value)
             {
-                return reinterpret_cast<const Field<Type>&>(input);
+                return reinterpret_cast<const FieldType&>(input);
             }
             else
             {
@@ -106,8 +163,25 @@ class PrecisionAdaptor
         Field<InputType>& ref_;
 
 
+    // Private Member Functions
+
+        //- Copy in field
+        void copyInput(const Field<InputType>& input)
+        {
+            this->clear();
+
+            Field<Type>* p = new Field<Type>(input.size());
+            this->reset(p);
+            std::copy(input.cbegin(), input.cend(), p->begin());
+        }
+
+
 public:
 
+    //- The adapted field type
+    typedef Field<Type> FieldType;
+
+
     // Constructors
 
         //- Construct from Field<InputType>, copying on input as required
@@ -118,13 +192,11 @@ public:
         {
             if (std::is_same<Type, InputType>::value)
             {
-                // Set reference - cast for compiler to handle different types
-                this->cref(reinterpret_cast<const Field<Type>&>(input));
+                this->cref(reinterpret_cast<const FieldType&>(input));
             }
             else
             {
-                this->reset(new Field<Type>(input.size()));
-                std::copy(input.cbegin(), input.cend(), this->ref().begin());
+                this->copyInput(input);
             }
         }
 
@@ -134,11 +206,20 @@ public:
     {
         if (this->isTmp())
         {
-            const Field<Type>& store = this->cref();
+            const FieldType& store = this->cref();
             ref_.resize(store.size());
             std::copy(store.cbegin(), store.cend(), ref_.begin());
         }
     }
+
+
+    // Member Functions
+
+        //- Allow modification without const-ref check
+        FieldType& ref()
+        {
+            return this->constCast();
+        }
 };
 
 
diff --git a/src/OpenFOAM/matrices/lduMatrix/solvers/GAMG/GAMGSolverSolve.C b/src/OpenFOAM/matrices/lduMatrix/solvers/GAMG/GAMGSolverSolve.C
index 0184d34ca08..25fc7a84814 100644
--- a/src/OpenFOAM/matrices/lduMatrix/solvers/GAMG/GAMGSolverSolve.C
+++ b/src/OpenFOAM/matrices/lduMatrix/solvers/GAMG/GAMGSolverSolve.C
@@ -41,7 +41,7 @@ Foam::solverPerformance Foam::GAMGSolver::solve
 ) const
 {
     PrecisionAdaptor<solveScalar, scalar> tpsi(psi_s);
-    solveScalarField& psi = tpsi.constCast();
+    solveScalarField& psi = tpsi.ref();
 
     ConstPrecisionAdaptor<solveScalar, scalar> tsource(source);
 
@@ -581,21 +581,16 @@ void Foam::GAMGSolver::solveCoarsestLevel
 {
     const label coarsestLevel = matrixLevels_.size() - 1;
 
-    label coarseComm = matrixLevels_[coarsestLevel].mesh().comm();
+    const label coarseComm = matrixLevels_[coarsestLevel].mesh().comm();
 
     if (directSolveCoarsest_)
     {
-        PrecisionAdaptor<scalar, solveScalar> tcorrField
-        (
-            coarsestCorrField
-        );
+        PrecisionAdaptor<scalar, solveScalar> tcorrField(coarsestCorrField);
+
         coarsestLUMatrixPtr_->solve
         (
-            tcorrField.constCast(),
-            ConstPrecisionAdaptor<scalar, solveScalar>
-            (
-                coarsestSource
-            )()
+            tcorrField.ref(),
+            ConstPrecisionAdaptor<scalar, solveScalar>(coarsestSource)()
         );
     }
     //else if
diff --git a/src/OpenFOAM/matrices/lduMatrix/solvers/PBiCG/PBiCG.C b/src/OpenFOAM/matrices/lduMatrix/solvers/PBiCG/PBiCG.C
index 9545b9cf893..65371df0129 100644
--- a/src/OpenFOAM/matrices/lduMatrix/solvers/PBiCG/PBiCG.C
+++ b/src/OpenFOAM/matrices/lduMatrix/solvers/PBiCG/PBiCG.C
@@ -73,7 +73,7 @@ Foam::solverPerformance Foam::PBiCG::solve
 ) const
 {
     PrecisionAdaptor<solveScalar, scalar> tpsi(psi_s);
-    solveScalarField& psi = tpsi.constCast();
+    solveScalarField& psi = tpsi.ref();
 
     // --- Setup class containing solver performance data
     solverPerformance solverPerf
diff --git a/src/OpenFOAM/matrices/lduMatrix/solvers/PBiCGStab/PBiCGStab.C b/src/OpenFOAM/matrices/lduMatrix/solvers/PBiCGStab/PBiCGStab.C
index 7ec60707c1b..2694a7c757b 100644
--- a/src/OpenFOAM/matrices/lduMatrix/solvers/PBiCGStab/PBiCGStab.C
+++ b/src/OpenFOAM/matrices/lduMatrix/solvers/PBiCGStab/PBiCGStab.C
@@ -282,11 +282,9 @@ Foam::solverPerformance Foam::PBiCGStab::solve
 ) const
 {
     PrecisionAdaptor<solveScalar, scalar> tpsi(psi_s);
-    solveScalarField& psi = tpsi.constCast();
-
     return scalarSolve
     (
-        psi,
+        tpsi.ref(),
         ConstPrecisionAdaptor<solveScalar, scalar>(source)(),
         cmpt
     );
diff --git a/src/OpenFOAM/matrices/lduMatrix/solvers/PCG/PCG.C b/src/OpenFOAM/matrices/lduMatrix/solvers/PCG/PCG.C
index 5c408d02dae..5131df1756b 100644
--- a/src/OpenFOAM/matrices/lduMatrix/solvers/PCG/PCG.C
+++ b/src/OpenFOAM/matrices/lduMatrix/solvers/PCG/PCG.C
@@ -220,7 +220,7 @@ Foam::solverPerformance Foam::PCG::solve
     PrecisionAdaptor<solveScalar, scalar> tpsi(psi_s);
     return scalarSolve
     (
-        tpsi.constCast(),
+        tpsi.ref(),
         ConstPrecisionAdaptor<solveScalar, scalar>(source)(),
         cmpt
     );
diff --git a/src/OpenFOAM/matrices/lduMatrix/solvers/smoothSolver/smoothSolver.C b/src/OpenFOAM/matrices/lduMatrix/solvers/smoothSolver/smoothSolver.C
index 47e11f4fdf3..65745e6d874 100644
--- a/src/OpenFOAM/matrices/lduMatrix/solvers/smoothSolver/smoothSolver.C
+++ b/src/OpenFOAM/matrices/lduMatrix/solvers/smoothSolver/smoothSolver.C
@@ -86,7 +86,7 @@ Foam::solverPerformance Foam::smoothSolver::solve
 ) const
 {
     PrecisionAdaptor<solveScalar, scalar> tpsi(psi_s);
-    solveScalarField& psi = tpsi.constCast();
+    solveScalarField& psi = tpsi.ref();
 
     // Setup class containing solver performance data
     solverPerformance solverPerf(typeName, fieldName_);
diff --git a/src/finiteArea/faMatrices/faScalarMatrix/faScalarMatrix.C b/src/finiteArea/faMatrices/faScalarMatrix/faScalarMatrix.C
index b7eefba1172..21f0a4dc2d7 100644
--- a/src/finiteArea/faMatrices/faScalarMatrix/faScalarMatrix.C
+++ b/src/finiteArea/faMatrices/faScalarMatrix/faScalarMatrix.C
@@ -119,7 +119,6 @@ Foam::tmp<Foam::scalarField> Foam::faMatrix<Foam::scalar>::residual() const
     );
 
     ConstPrecisionAdaptor<scalar, solveScalar> tres_s(tres);
-
     addBoundarySource(tres_s.ref());
 
     return tres_s;
diff --git a/src/finiteVolume/fvMatrices/fvMatrix/fvMatrixSolve.C b/src/finiteVolume/fvMatrices/fvMatrix/fvMatrixSolve.C
index dec7e4b1f32..1d37d6d73ce 100644
--- a/src/finiteVolume/fvMatrices/fvMatrix/fvMatrixSolve.C
+++ b/src/finiteVolume/fvMatrices/fvMatrix/fvMatrixSolve.C
@@ -184,7 +184,7 @@ Foam::SolverPerformance<Type> Foam::fvMatrix<Type>::solveSegregated
                 bouCoeffsCmpt,
                 interfaces,
                 psiCmpt_ss(),
-                sourceCmpt_ss.constCast(),
+                sourceCmpt_ss.ref(),
                 cmpt
             );
 
@@ -194,7 +194,7 @@ Foam::SolverPerformance<Type> Foam::fvMatrix<Type>::solveSegregated
                 bouCoeffsCmpt,
                 interfaces,
                 psiCmpt_ss(),
-                sourceCmpt_ss.constCast(),
+                sourceCmpt_ss.ref(),
                 cmpt
             );
         }
diff --git a/src/finiteVolume/fvMatrices/fvScalarMatrix/fvScalarMatrix.C b/src/finiteVolume/fvMatrices/fvScalarMatrix/fvScalarMatrix.C
index 1d15cbb7871..ba5a842267c 100644
--- a/src/finiteVolume/fvMatrices/fvScalarMatrix/fvScalarMatrix.C
+++ b/src/finiteVolume/fvMatrices/fvScalarMatrix/fvScalarMatrix.C
@@ -215,8 +215,10 @@ Foam::tmp<Foam::scalarField> Foam::fvMatrix<Foam::scalar>::residual() const
             0
         )
     );
+
     ConstPrecisionAdaptor<scalar, solveScalar> tres_s(tres);
-    addBoundarySource(tres_s.constCast());
+    addBoundarySource(tres_s.ref());
+
     return tres_s;
 }
 
-- 
GitLab