From 4f8edb17bad905c9491dce268e54661fe0cbf026 Mon Sep 17 00:00:00 2001
From: mattijs <mattijs>
Date: Thu, 13 Jun 2019 20:52:48 +0100
Subject: [PATCH] ENH: metis: use PrecisionAdaptor to support 64 bit indices

---
 .../Field/PrecisionAdaptor/PrecisionAdaptor.H | 65 ++++++++--------
 src/OpenFOAM/memory/tmp/tmpNrc.H              |  4 +
 src/OpenFOAM/memory/tmp/tmpNrcI.H             | 14 ++++
 .../decompose/metisDecomp/metisDecomp.C       | 76 ++++++++++---------
 wmake/scripts/have_metis                      | 14 +---
 5 files changed, 92 insertions(+), 81 deletions(-)

diff --git a/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H b/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H
index 0c33ed73886..39c9deae2bd 100644
--- a/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H
+++ b/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H
@@ -36,6 +36,7 @@ Description
 #ifndef PrecisionAdaptor_H
 #define PrecisionAdaptor_H
 
+#include "tmpNrc.H"
 #include "Field.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -44,34 +45,34 @@ namespace Foam
 {
 
 //- A const Field wrapper with possible data conversion
-template<class Type, class InputType>
+template<class Type, class InputType, template<class> class Container = Field>
 class ConstPrecisionAdaptor
 :
-    public tmp<Field<Type>>
+    public tmpNrc<Container<Type>>
 {
     // Private Member Functions
 
         //- Copy in field
-        void copyInput(const Field<InputType>& input)
+        void copyInput(const Container<InputType>& input)
         {
             this->clear();
 
-            Field<Type>* p = new Field<Type>(input.size());
+            Container<Type>* p = new Container<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)
+        void moveInput(tmp<Container<InputType>>& input)
         {
             if (std::is_same<Type, InputType>::value)
             {
-                auto& tinput = reinterpret_cast<tmp<FieldType>&>(input);
+                auto& tinput = reinterpret_cast<tmp<Container<Type>>&>(input);
 
                 if (tinput.isTmp())
                 {
-                    this->clear();
-                    this->swap(tinput);
+                    // Reset to tmp
+                    this->reset(tinput.ptr());
                 }
                 else
                 {
@@ -89,15 +90,15 @@ class ConstPrecisionAdaptor
 public:
 
     //- The adapted field type
-    typedef Field<Type> FieldType;
+    typedef Container<Type> FieldType;
 
 
     // Constructors
 
-        //- Construct from Field<InputType>, copying on input as required
-        ConstPrecisionAdaptor(const Field<InputType>& input)
+        //- Construct from Container<InputType>, copying on input as required
+        ConstPrecisionAdaptor(const Container<InputType>& input)
         :
-            tmp<Field<Type>>()
+            tmpNrc<Container<Type>>()
         {
             if (std::is_same<Type, InputType>::value)
             {
@@ -110,31 +111,31 @@ public:
         }
 
 
-        //- Construct from tmp Field, copy/move as required
-        ConstPrecisionAdaptor(tmp<Field<InputType>>&& input)
+        //- Construct from tmp Container, copy/move as required
+        ConstPrecisionAdaptor(tmp<Container<InputType>>&& input)
         :
-            tmp<Field<Type>>()
+            tmpNrc<Container<Type>>()
         {
             this->moveInput(input);
         }
 
 
-        //- Construct from tmp Field, copy/move as required
-        ConstPrecisionAdaptor(const tmp<Field<InputType>>& input)
+        //- Construct from tmp Container, copy/move as required
+        ConstPrecisionAdaptor(const tmp<Container<InputType>>& input)
         :
-            tmp<Field<Type>>()
+            tmpNrc<Container<Type>>()
         {
-            this->moveInput(const_cast<tmp<Field<InputType>>&>(input));
+            this->moveInput(const_cast<tmp<Container<InputType>>&>(input));
         }
 
 
     // Member Functions
 
         //- Return the field
-        static const Field<Type>& get
+        static const Container<Type>& get
         (
-            const Field<InputType>& input,
-            Field<Type>& dst
+            const Container<InputType>& input,
+            Container<Type>& dst
         )
         {
             if (std::is_same<Type, InputType>::value)
@@ -152,25 +153,23 @@ public:
 
 
 //- A Field wrapper with possible data conversion
-template<class Type, class InputType>
+template<class Type, class InputType, template<class> class Container = Field>
 class PrecisionAdaptor
 :
-    public tmp<Field<Type>>
+    public tmpNrc<Container<Type>>
 {
     // Private Data
 
         //- Reference to underlying field
-        Field<InputType>& ref_;
+        Container<InputType>& ref_;
 
 
     // Private Member Functions
 
         //- Copy in field
-        void copyInput(const Field<InputType>& input)
+        void copyInput(const Container<InputType>& input)
         {
-            this->clear();
-
-            Field<Type>* p = new Field<Type>(input.size());
+            Container<Type>* p = new Container<Type>(input.size());
             this->reset(p);
             std::copy(input.cbegin(), input.cend(), p->begin());
         }
@@ -179,15 +178,15 @@ class PrecisionAdaptor
 public:
 
     //- The adapted field type
-    typedef Field<Type> FieldType;
+    typedef Container<Type> FieldType;
 
 
     // Constructors
 
-        //- Construct from Field<InputType>, copying on input as required
-        PrecisionAdaptor(Field<InputType>& input)
+        //- Construct from Container<InputType>, copying on input as required
+        PrecisionAdaptor(Container<InputType>& input)
         :
-            tmp<Field<Type>>(),
+            tmpNrc<Container<Type>>(),
             ref_(input)
         {
             if (std::is_same<Type, InputType>::value)
diff --git a/src/OpenFOAM/memory/tmp/tmpNrc.H b/src/OpenFOAM/memory/tmp/tmpNrc.H
index d5a3b7b6f79..7617af37124 100644
--- a/src/OpenFOAM/memory/tmp/tmpNrc.H
+++ b/src/OpenFOAM/memory/tmp/tmpNrc.H
@@ -42,6 +42,7 @@ See also
 
 #include "refCount.H"
 #include "word.H"
+#include "tmp.H"
 #include <utility>
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -229,6 +230,9 @@ public:
         //- Transfer ownership of the managed pointer.
         //  Fatal for a null managed pointer or if the object is const.
         inline void operator=(const tmpNrc<T>& t);
+
+        //- Conversion to tmp
+        inline operator tmp<T>();
 };
 
 
diff --git a/src/OpenFOAM/memory/tmp/tmpNrcI.H b/src/OpenFOAM/memory/tmp/tmpNrcI.H
index 4f8148b0396..1e3a7136d79 100644
--- a/src/OpenFOAM/memory/tmp/tmpNrcI.H
+++ b/src/OpenFOAM/memory/tmp/tmpNrcI.H
@@ -427,4 +427,18 @@ inline void Foam::tmpNrc<T>::operator=(const tmpNrc<T>& t)
 }
 
 
+template<class T>
+inline Foam::tmpNrc<T>::operator tmp<T>()
+{
+    if (isTmp())
+    {
+        return tmp<T>(ptr());
+    }
+    else
+    {
+        return tmp<T>(cref());
+    }
+}
+
+
 // ************************************************************************* //
diff --git a/src/parallel/decompose/metisDecomp/metisDecomp.C b/src/parallel/decompose/metisDecomp/metisDecomp.C
index 0509a28a3b4..ce4ea4c7a76 100644
--- a/src/parallel/decompose/metisDecomp/metisDecomp.C
+++ b/src/parallel/decompose/metisDecomp/metisDecomp.C
@@ -28,6 +28,7 @@ License
 #include "metisDecomp.H"
 #include "addToRunTimeSelectionTable.H"
 #include "Time.H"
+#include "PrecisionAdaptor.H"
 
 // Probably not needed...
 #define MPICH_SKIP_MPICXX
@@ -39,13 +40,13 @@ License
 //
 // Metis has an 'idx_t' type, but the IDXTYPEWIDTH define is perhaps
 // more future-proof?
-#ifdef IDXTYPEWIDTH
-static_assert
-(
-    sizeof(Foam::label) == (IDXTYPEWIDTH/8),
-    "sizeof(Foam::label) == (IDXTYPEWIDTH/8), check your metis headers"
-);
-#endif
+//#ifdef IDXTYPEWIDTH
+//static_assert
+//(
+//    sizeof(Foam::label) == (IDXTYPEWIDTH/8),
+//    "sizeof(Foam::label) == (IDXTYPEWIDTH/8), check your metis headers"
+//);
+//#endif
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -86,10 +87,10 @@ Foam::label Foam::metisDecomp::decomposeSerial
 
     const dictionary* coeffsDictPtr = decompDict_.findDict("metisCoeffs");
 
-    label numCells = xadj.size()-1;
+    idx_t numCells = xadj.size()-1;
 
     // Decomposition options
-    List<label> options(METIS_NOPTIONS);
+    List<idx_t> options(METIS_NOPTIONS);
     METIS_SetDefaultOptions(options.begin());
 
     // Processor weights initialised with no size, only used if specified in
@@ -97,10 +98,10 @@ Foam::label Foam::metisDecomp::decomposeSerial
     Field<real_t> processorWeights;
 
     // Cell weights (so on the vertices of the dual)
-    List<label> cellWeights;
+    List<idx_t> cellWeights;
 
     // Face weights (so on the edges of the dual)
-    List<label> faceWeights;
+    List<idx_t> faceWeights;
 
     // Check for externally provided cellweights and if so initialise weights
     // Note: min, not gMin since routine runs on master only.
@@ -184,51 +185,56 @@ Foam::label Foam::metisDecomp::decomposeSerial
         }
     }
 
-    label ncon = 1;
-    label nProcs = nDomains_;
+    idx_t ncon = 1;
+    idx_t nProcs = nDomains_;
+
+    // Addressing
+    ConstPrecisionAdaptor<idx_t, label, List> xadj_metis(xadj);
+    ConstPrecisionAdaptor<idx_t, label, List> adjncy_metis(adjncy);
 
     // Output: cell -> processor addressing
-    decomp.setSize(numCells);
+    PrecisionAdaptor<idx_t, label, List> decomp_metis(decomp);
+    decomp_metis.ref().setSize(numCells);
 
     // Output: number of cut edges
-    label edgeCut = 0;
+    idx_t edgeCut = 0;
 
     if (method == "recursive")
     {
         METIS_PartGraphRecursive
         (
-            &numCells,          // num vertices in graph
-            &ncon,              // num balancing constraints
-            const_cast<labelUList&>(xadj).begin(),   // indexing into adjncy
-            const_cast<labelUList&>(adjncy).begin(), // neighbour info
-            cellWeights.begin(),// vertex wts
-            nullptr,               // vsize: total communication vol
-            faceWeights.begin(),// edge wts
-            &nProcs,            // nParts
+            &numCells,                  // num vertices in graph
+            &ncon,                      // num balancing constraints
+            xadj_metis.ref().begin(),   // indexing into adjncy
+            adjncy_metis.ref().begin(), // neighbour info
+            cellWeights.begin(),        // vertex wts
+            nullptr,                    // vsize: total communication vol
+            faceWeights.begin(),        // edge wts
+            &nProcs,                    // nParts
             processorWeights.begin(),   // tpwgts
-            nullptr,               // ubvec: processor imbalance (default)
+            nullptr,                    // ubvec: processor imbalance (default)
             options.begin(),
             &edgeCut,
-            decomp.begin()
+            decomp_metis.ref().begin()
         );
     }
     else
     {
         METIS_PartGraphKway
         (
-            &numCells,          // num vertices in graph
-            &ncon,              // num balancing constraints
-            const_cast<labelUList&>(xadj).begin(),   // indexing into adjncy
-            const_cast<labelUList&>(adjncy).begin(), // neighbour info
-            cellWeights.begin(),// vertex wts
-            nullptr,               // vsize: total communication vol
-            faceWeights.begin(),// edge wts
-            &nProcs,            // nParts
+            &numCells,                  // num vertices in graph
+            &ncon,                      // num balancing constraints
+            xadj_metis.ref().begin(),   // indexing into adjncy
+            adjncy_metis.ref().begin(), // neighbour info
+            cellWeights.begin(),        // vertex wts
+            nullptr,                    // vsize: total communication vol
+            faceWeights.begin(),        // edge wts
+            &nProcs,                    // nParts
             processorWeights.begin(),   // tpwgts
-            nullptr,               // ubvec: processor imbalance (default)
+            nullptr,                    // ubvec: processor imbalance (default)
             options.begin(),
             &edgeCut,
-            decomp.begin()
+            decomp_metis.ref().begin()
         );
     }
 
diff --git a/wmake/scripts/have_metis b/wmake/scripts/have_metis
index a72c1ecdf50..52d1235c320 100644
--- a/wmake/scripts/have_metis
+++ b/wmake/scripts/have_metis
@@ -107,7 +107,7 @@ have_metis()
 
     # ----------------------------------
 
-    local good label
+    local label
 
     # Ensure consistent sizes between OpenFOAM and metis header
     # Extract IDXTYPEWIDTH from metis.h: regex as per ThirdParty Allwmake
@@ -116,18 +116,6 @@ have_metis()
         "$header")
     : "${label:=unknown}"
 
-    if [ "$WM_LABEL_SIZE" = "$label" ]
-    then
-        good=true
-    else
-        if [ -n "$warn" ]
-        then
-            echo "$warn (label=$WM_LABEL_SIZE, ${header##*/} has '$label')"
-        fi
-        no_metis
-        return 1
-    fi
-
     # OK
     echo "metis (label=$label) - $prefix"
     export HAVE_METIS=true
-- 
GitLab