From f65d7bdc1d682b4e40544800ef33814aff4b4104 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Mon, 24 Feb 2025 00:10:02 +0100
Subject: [PATCH] Fix serial building and add ParMETIS/PTScotch version info

---
 CMakeLists.txt                    | 34 ++++++++++++++++++++++++-------
 README.md                         |  6 +++---
 src/utils/BuildInfo.cpp           | 29 ++++++++++++++++++++++++++
 src/utils/BuildInfo.hpp           |  2 ++
 src/utils/PugsUtils.cpp           |  2 ++
 tests/CMakeLists.txt              |  1 +
 tests/test_BuildInfo.cpp          | 32 +++++++++++++++++++++++++++++
 tests/test_Partitioner.cpp        |  8 ++++----
 tests/test_PartitionerOptions.cpp |  5 +++--
 tests/test_PugsUtils.cpp          |  2 ++
 10 files changed, 105 insertions(+), 16 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7c0f69fcf..4cca59ccc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -142,7 +142,7 @@ endif()
 # Search for ParMETIS
 
 find_package(ParMETIS)
-if(PARMETIS_LIBRARIES)
+if(PARMETIS_LIBRARIES AND MPI_FOUND)
   add_library(PkgConfig::ParMETIS STATIC IMPORTED)
   set_property(TARGET PkgConfig::ParMETIS PROPERTY
     IMPORTED_LOCATION "${PARMETIS_LIBRARIES}")
@@ -158,9 +158,7 @@ endif()
 
 find_package(PTScotch)
 
-set(PUGS_HAS_PTSCOTCH ${PTScotch_FOUND})
-
-if (PTScotch_FOUND)
+if (PTScotch_FOUND AND MPI_FOUND)
   add_library(PkgConfig::PTScotch STATIC IMPORTED)
   set_property(TARGET PkgConfig::PTScotch PROPERTY
     IMPORTED_LOCATION "${PTSCOTCH_LIBRARY}")
@@ -169,8 +167,10 @@ if (PTScotch_FOUND)
 
   set(PTSCOTCH_TARGET PkgConfig::PTScotch)
   include_directories(SYSTEM "${PTSCOTCH_INCLUDE_DIR}")
+  set(PUGS_HAS_PTSCOTCH TRUE)
 else()
   set(PTSCOTCH_LIBRARY "")
+  unset(PUGS_HAS_PTSCOTCH)
 endif()
 
 #------------------------------------------------------
@@ -842,9 +842,9 @@ if (MPI_FOUND)
   message(" MPI: ${MPI_CXX_LIBRARY_VERSION_STRING}")
 else()
   if (PUGS_ENABLE_MPI MATCHES "^OFF$")
-    message(" MPI: deactivated!")
-  elseif(NOT PARMETIS_LIBRARIES)
-    message(" MPI: deactivated: ParMETIS cannot be found!")
+    message(" MPI: explicitly deactivated!")
+  elseif((NOT PUGS_HAS_PARMETIS) and (NOT PUGS_HAS_PTSCOTCH))
+    message(" MPI: deactivated: ParMETIS and PTScotch cannot be found!")
   else()
     if (PUGS_ENABLE_MPI MATCHES "^(AUTO|ON)$")
       message(" MPI: not found!")
@@ -854,6 +854,26 @@ else()
   endif()
 endif()
 
+if (PUGS_HAS_PARMETIS)
+  message(" ParMETIS: ${PARMETIS_LIBRARIES}")
+else()
+  if (PUGS_HAS_MPI)
+  message(" ParMETIS: not found!")
+  else()
+  message(" ParMETIS: deactivated (MPI not found)")
+  endif()
+endif()
+
+if (PUGS_HAS_PTSCOTCH)
+  message(" PTScotch: ${PTSCOTCH_LIBRARIES}")
+else()
+  if (PUGS_HAS_MPI)
+  message(" PTScotch: not found!")
+  else()
+  message(" PTScotch: deactivated (MPI not found)")
+  endif()
+endif()
+
 if (PETSC_FOUND)
   message(" PETSc: ${PETSC_VERSION}")
 else()
diff --git a/README.md b/README.md
index 473b27b07..fc6d9da70 100644
--- a/README.md
+++ b/README.md
@@ -54,12 +54,12 @@ functionalities or development tools.
 
 `pugs` integrates MPI support and should compile with any MPI-3
 implementation. However in order to dispatch meshes on MPI processes
-`pugs` requires `ParMETIS`. Without, MPI support will be automatically
-deactivated.
+`pugs` requires `ParMETIS` or `PTScotch`. Without one of them, the MPI
+support will be automatically deactivated.
 
 The easiest way to enable MPI support on Debian-like systems is to run
 ```shell
-apt install libparmetis-dev
+apt install libparmetis-dev libscotch-dev
 ```
 
 #### `PETSc`
diff --git a/src/utils/BuildInfo.cpp b/src/utils/BuildInfo.cpp
index 2413bdbae..8cdb5fc83 100644
--- a/src/utils/BuildInfo.cpp
+++ b/src/utils/BuildInfo.cpp
@@ -9,6 +9,14 @@
 #include <mpi.h>
 #endif   //  PUGS_HAS_MPI
 
+#ifdef PUGS_HAS_PARMETIS
+#include <parmetis.h>
+#endif   //  PUGS_HAS_PARMETIS
+
+#ifdef PUGS_HAS_PTSCOTCH
+#include <ptscotch.h>
+#endif   //  PUGS_HAS_PTSCOTCH
+
 #ifdef PUGS_HAS_PETSC
 #include <petsc.h>
 #endif   // PUGS_HAS_PETSC
@@ -64,6 +72,27 @@ BuildInfo::mpiLibrary()
 #endif   // PUGS_HAS_MPI
 }
 
+std::string
+BuildInfo::parmetisLibrary()
+{
+#ifdef PUGS_HAS_PARMETIS
+  return stringify(PARMETIS_MAJOR_VERSION) + "." + stringify(PARMETIS_MINOR_VERSION) + "." +
+         stringify(PARMETIS_SUBMINOR_VERSION);
+#else    // PUGS_HAS_PARMETIS
+  return "none";
+#endif   // PUGS_HAS_PARMETIS
+}
+
+std::string
+BuildInfo::ptscotchLibrary()
+{
+#ifdef PUGS_HAS_PTSCOTCH
+  return stringify(SCOTCH_VERSION) + "." + stringify(SCOTCH_RELEASE) + "." + stringify(SCOTCH_PATCHLEVEL);
+#else    // PUGS_HAS_PTSCOTCH
+  return "none";
+#endif   // PUGS_HAS_PTSCOTCH
+}
+
 std::string
 BuildInfo::petscLibrary()
 {
diff --git a/src/utils/BuildInfo.hpp b/src/utils/BuildInfo.hpp
index 86f7c04f0..0142b5d08 100644
--- a/src/utils/BuildInfo.hpp
+++ b/src/utils/BuildInfo.hpp
@@ -9,6 +9,8 @@ struct BuildInfo
   static std::string compiler();
   static std::string kokkosDevices();
   static std::string mpiLibrary();
+  static std::string parmetisLibrary();
+  static std::string ptscotchLibrary();
   static std::string petscLibrary();
   static std::string slepcLibrary();
   static std::string eigen3Library();
diff --git a/src/utils/PugsUtils.cpp b/src/utils/PugsUtils.cpp
index ac64a50cf..356869699 100644
--- a/src/utils/PugsUtils.cpp
+++ b/src/utils/PugsUtils.cpp
@@ -62,6 +62,8 @@ pugsBuildInfo()
   os << "compiler: " << rang::style::bold << BuildInfo::compiler() << rang::style::reset << '\n';
   os << "kokkos:   " << rang::style::bold << BuildInfo::kokkosDevices() << rang::style::reset << '\n';
   os << "MPI:      " << rang::style::bold << BuildInfo::mpiLibrary() << rang::style::reset << '\n';
+  os << "ParMETIS: " << rang::style::bold << BuildInfo::parmetisLibrary() << rang::style::reset << '\n';
+  os << "PTScotch: " << rang::style::bold << BuildInfo::ptscotchLibrary() << rang::style::reset << '\n';
   os << "PETSc:    " << rang::style::bold << BuildInfo::petscLibrary() << rang::style::reset << '\n';
   os << "SLEPc:    " << rang::style::bold << BuildInfo::slepcLibrary() << rang::style::reset << '\n';
   os << "Eigen3:   " << rang::style::bold << BuildInfo::eigen3Library() << rang::style::reset << '\n';
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 1dd13e6e3..e0449ebcf 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -142,6 +142,7 @@ add_executable (unit_tests
   test_OStream.cpp
   test_ParallelChecker_write.cpp
   test_ParseError.cpp
+  test_PartitionerOptions.cpp
   test_PETScUtils.cpp
   test_PrimalToDiamondDualConnectivityDataMapper.cpp
   test_PrimalToDual1DConnectivityDataMapper.cpp
diff --git a/tests/test_BuildInfo.cpp b/tests/test_BuildInfo.cpp
index 9414902f4..02cf31adc 100644
--- a/tests/test_BuildInfo.cpp
+++ b/tests/test_BuildInfo.cpp
@@ -12,6 +12,14 @@
 #include <mpi.h>
 #endif   //  PUGS_HAS_MPI
 
+#ifdef PUGS_HAS_PARMETIS
+#include <parmetis.h>
+#endif   //  PUGS_HAS_PARMETIS
+
+#ifdef PUGS_HAS_PTSCOTCH
+#include <ptscotch.h>
+#endif   //  PUGS_HAS_PTSCOTCH
+
 #ifdef PUGS_HAS_PETSC
 #include <petsc.h>
 #endif   // PUGS_HAS_PETSC
@@ -57,6 +65,30 @@ TEST_CASE("BuildInfo", "[utils]")
 #endif   // PUGS_HAS_MPI
   }
 
+  SECTION("ParMETIS")
+  {
+#ifdef PUGS_HAS_PARMETIS
+    const std::string parmetis_library = stringify(PARMETIS_MAJOR_VERSION) + "." + stringify(PARMETIS_MINOR_VERSION) +
+                                         "." + stringify(PARMETIS_SUBMINOR_VERSION);
+
+    REQUIRE(BuildInfo::parmetisLibrary() == parmetis_library);
+#else
+    REQUIRE(BuildInfo::parmetisLibrary() == "none");
+#endif   // PUGS_HAS_PARMETIS
+  }
+
+  SECTION("PTScotch")
+  {
+#ifdef PUGS_HAS_PTSCOTCH
+    const std::string ptscotch_library =
+      stringify(SCOTCH_VERSION) + "." + stringify(SCOTCH_RELEASE) + "." + stringify(SCOTCH_PATCHLEVEL);
+
+    REQUIRE(BuildInfo::ptscotchLibrary() == ptscotch_library);
+#else
+    REQUIRE(BuildInfo::ptscotchLibrary() == "none");
+#endif   // PUGS_HAS_PTSCOTCH
+  }
+
   SECTION("petsc")
   {
 #ifdef PUGS_HAS_PETSC
diff --git a/tests/test_Partitioner.cpp b/tests/test_Partitioner.cpp
index 3638a3926..67ddbb111 100644
--- a/tests/test_Partitioner.cpp
+++ b/tests/test_Partitioner.cpp
@@ -88,8 +88,8 @@ TEST_CASE("Partitioner", "[utils]")
         REQUIRE(assigned_ranks.size() == parallel::size());
       }
 #else    // PUGS_HAS_PARMETIS
-      REQUIRE(min(partitionned == 0));
-      REQUIRE(max(partitionned == 0));
+      REQUIRE(min(partitioned) == 0);
+      REQUIRE(max(partitioned) == 0);
 #endif   // PUGS_HAS_PARMETIS
     }
 
@@ -113,8 +113,8 @@ TEST_CASE("Partitioner", "[utils]")
         REQUIRE(assigned_ranks.size() == parallel::size());
       }
 #else    // PUGS_HAS_PTSCOTCH
-      REQUIRE(min(partitionned == 0));
-      REQUIRE(max(partitionned == 0));
+      REQUIRE(min(partitioned) == 0);
+      REQUIRE(max(partitioned) == 0);
 #endif   // PUGS_HAS_PTSCOTCH
     }
   }
diff --git a/tests/test_PartitionerOptions.cpp b/tests/test_PartitionerOptions.cpp
index 67c016221..9f0605b4e 100644
--- a/tests/test_PartitionerOptions.cpp
+++ b/tests/test_PartitionerOptions.cpp
@@ -9,9 +9,10 @@ TEST_CASE("PartitionerOptions", "[utils]")
 {
   SECTION("name")
   {
-    REQUIRE(name(PartitionerLibrary::parmetis) == "ParMetis");
+    REQUIRE(name(PartitionerLibrary::parmetis) == "ParMETIS");
     REQUIRE(name(PartitionerLibrary::ptscotch) == "PTScotch");
-    REQUIRE_THROWS_WITH(PartitionerLibrary::PT__end, "unexpected error: Partitioner library name is not defined!");
+    REQUIRE_THROWS_WITH(name(PartitionerLibrary::PT__end),
+                        "unexpected error: Partitioner library name is not defined!");
 
     WARN("not finished");
   }
diff --git a/tests/test_PugsUtils.cpp b/tests/test_PugsUtils.cpp
index 5ba8817fc..175ed9294 100644
--- a/tests/test_PugsUtils.cpp
+++ b/tests/test_PugsUtils.cpp
@@ -49,6 +49,8 @@ TEST_CASE("PugsUtils", "[utils]")
       os << "compiler: " << rang::style::bold << BuildInfo::compiler() << rang::style::reset << '\n';
       os << "kokkos:   " << rang::style::bold << BuildInfo::kokkosDevices() << rang::style::reset << '\n';
       os << "MPI:      " << rang::style::bold << BuildInfo::mpiLibrary() << rang::style::reset << '\n';
+      os << "ParMETIS: " << rang::style::bold << BuildInfo::parmetisLibrary() << rang::style::reset << '\n';
+      os << "PTScotch: " << rang::style::bold << BuildInfo::ptscotchLibrary() << rang::style::reset << '\n';
       os << "PETSc:    " << rang::style::bold << BuildInfo::petscLibrary() << rang::style::reset << '\n';
       os << "SLEPc:    " << rang::style::bold << BuildInfo::slepcLibrary() << rang::style::reset << '\n';
       os << "Eigen3:   " << rang::style::bold << BuildInfo::eigen3Library() << rang::style::reset << '\n';
-- 
GitLab