From 28811b14cac36b4bf6c4203525f517c65aab9ce6 Mon Sep 17 00:00:00 2001
From: MARAIT Gilles <gilles.marait@inria.fr>
Date: Fri, 2 Feb 2024 11:40:50 +0100
Subject: [PATCH] Add FEM with compose

---
 src/testCOMPOSE.cpp | 222 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 201 insertions(+), 21 deletions(-)

diff --git a/src/testCOMPOSE.cpp b/src/testCOMPOSE.cpp
index 0c3c9f8..69736c5 100644
--- a/src/testCOMPOSE.cpp
+++ b/src/testCOMPOSE.cpp
@@ -7,6 +7,8 @@
 char * C_PACKAGE_NAME = const_cast<char *>(PACKAGE_NAME) ;
 char * C_FILE = const_cast<char *>(__FILE__);
 
+// Redefine the macros to be C++ compatible
+
 /*! \brief Displays an error message and that's all. */
 #define C_SETWARN(n,s, ...)   {MpfWarning(__LINE__,C_PACKAGE_NAME,C_FILE,__func__,n,s, ## __VA_ARGS__);}
 /*! \brief Displays an error message and quits the current routine. */
@@ -26,20 +28,176 @@ char * C_FILE = const_cast<char *>(__FILE__);
 /*! \brief Evaluates the expression x, if it is false then it displays an error message and aborts the code. */
 #define C_ASSERTA(x) { if (!(x)) { C_SETERRA(1, "Assert failure %s", #x); }}
 
-
 #include <maphys.hpp>
 #include <memory>
 #include <cstring>
 #include <string>
+#include <span>
 
 using namespace maphys;
 
 template<typename Scalar>
-int testCOMPOSE_Scalar(double * relative_error){
+struct nonzero_type { using type = std::false_type; };
+template<> struct nonzero_type<float> { using type = SnonZero; };
+template<> struct nonzero_type<double> { using type = DnonZero; };
+template<> struct nonzero_type<std::complex<float>> { using type = CnonZero; };
+template<> struct nonzero_type<std::complex<double>> { using type = ZnonZero; };
+
+template<typename Scalar>
+int testCOMPOSE_FEM(double * relative_error){
+
+  using NonZero = typename nonzero_type<Scalar>::type;
 
   int ierr = 0;
   double temps_initial, temps_final, temps_cpu;
-  size_t vectorSize = (size_t)nbPts*nbRHS*(complexALGO?2:1);
+  size_t vectorSize = (size_t) nbPts*nbRHS*(complexALGO?2:1);
+
+  /* Realise le produit matrice vecteur classique : A.rhs -> solCLA */
+
+  Mpf_printf(MPI_COMM_WORLD, "\n**** Computing Classical product...\n") ;
+  void *solCLA=NULL;
+  ierr = produitClassique(&solCLA, MPI_COMM_WORLD) ; C_CHKERRQ(ierr) ;
+
+  const int N = nbPts;
+
+  auto myCtx = std::make_unique<contextTestFEMBEM>();
+  std::memset(myCtx.get(), 0, sizeof(contextTestFEMBEM));
+  myCtx->colDim = N;
+
+  temps_initial = getTime ();
+  Mpf_printf( MPI_COMM_WORLD, "\n**** Creating COMPOSE ...\n" );
+
+  int row_min = 1;
+  int row_max = N;
+  int col_min = 1;
+  int col_max = N;
+  int nnz;
+  NonZero * matComp = (NonZero *) malloc(sizeof(NonZero)); // For some reason, realloc is used on this
+
+  freeFemMatrix();
+  createFemMatrix();
+  computeSparseBlockFEMBEM(&row_min, &row_max, &col_min, &col_max,
+                           &Mpf_i_zero, &Mpf_i_one, &Mpf_i_one, &Mpf_i_one,
+                           &nnz, (void **) &matComp, (void *) myCtx.get());
+  freeFemMatrix();
+
+  std::span<NonZero> matspan(matComp, nnz);
+
+  IndexArray<int> Ai(nnz), Aj(nnz);
+  IndexArray<Scalar> Av(nnz);
+  int k = 0;
+  for(auto elt : matspan){
+    Ai[k] = elt.i; Aj[k] = elt.j;
+    if constexpr(is_complex<Scalar>::value) {
+      Av[k] =  Scalar{elt.v.r, elt.v.i};
+    }
+    else{
+      Av[k] = elt.v;
+    }
+    k++;
+  }
+
+  SparseMatrixCOO<Scalar> A(N, N, static_cast<size_t>(nnz), std::move(Ai), std::move(Aj), std::move(Av));
+
+  temps_final = getTime();
+  temps_cpu = temps_final - temps_initial ;
+  Mpf_printf(MPI_COMM_WORLD,"<PERFTESTS> TpsCpuCOMPOSECreation = %f \n", temps_cpu) ;
+
+  DenseMatrix<Scalar> B;
+  DenseMatrix<Scalar> X;
+  void *solCOMPOSE = nullptr;
+
+  switch(testedAlgo){
+  case _gemvCOMPOSE:
+
+    Mpf_printf(MPI_COMM_WORLD, "\n**** Computing COMPOSE product...\n") ;
+    temps_initial = getTime();
+
+    if (simplePrec)
+      doubleToSimple(rhs, vectorSize);
+
+    B = DenseMatrix<Scalar>::view(N, nbRHS, (Scalar*) rhs, N);
+
+    solCOMPOSE = MpfCalloc(vectorSize, sizeof(D_type)) ; C_CHKPTRQ(solCOMPOSE) ;
+    X = DenseMatrix<Scalar>::view(N, nbRHS, (Scalar*) solCOMPOSE, N);
+
+    X = A * B;
+
+    temps_final = getTime();
+    temps_cpu = temps_final - temps_initial ;
+
+    if (simplePrec) {
+      simpleToDouble(solCOMPOSE, vectorSize);
+      simpleToDouble(rhs, vectorSize);
+    }
+
+    Mpf_printf(MPI_COMM_WORLD,"<PERFTESTS> TpsCpuGEMVCOMPOSE= %f \n", temps_cpu) ;
+
+    // Compare les 2 produits matrice-vecteur
+
+    Mpf_printf(MPI_COMM_WORLD, "\n**** Comparing results...\n") ;
+    ierr=computeRelativeError(solCOMPOSE, solCLA, relative_error); C_CHKERRQ(ierr);
+
+    Mpf_printf(MPI_COMM_WORLD, "<PERFTESTS> Error = %.4e \n", *relative_error);
+
+    if(solCOMPOSE) MpfFree(solCOMPOSE);
+
+    break;
+
+  case _solveCOMPOSE:
+    {
+      Mpf_printf(MPI_COMM_WORLD, "\n\n**** Factorizing COMPOSE Mat...\n") ;
+      temps_initial = getTime();
+
+      Pastix<SparseMatrixCOO<Scalar>, DenseMatrix<Scalar>> solver(A);
+      //Mumps<SparseMatrixCOO<Scalar>, DenseMatrix<Scalar>> solver(A);
+      solver.factorize();
+
+      temps_final = getTime();
+      temps_cpu = temps_final - temps_initial;
+
+      Mpf_printf(MPI_COMM_WORLD,"<PERFTESTS> TpsCpuCOMPOSEFacto = %f \n", temps_cpu) ;
+      temps_initial = getTime();
+
+      if (simplePrec)
+	doubleToSimple(solCLA, vectorSize);
+
+      B = DenseMatrix<Scalar>::view(N, nbRHS, (Scalar*) solCLA, N);
+      //B.display("B");
+
+      solCOMPOSE = MpfCalloc(vectorSize, sizeof(D_type)) ; C_CHKPTRQ(solCOMPOSE) ;
+      X = DenseMatrix<Scalar>::view(N, nbRHS, (Scalar*) solCOMPOSE, N);
+
+      X = solver * B;
+
+      temps_final = getTime();
+      temps_cpu = temps_final - temps_initial;
+
+      if (simplePrec) {
+	simpleToDouble(solCOMPOSE, vectorSize);
+      }
+
+      Mpf_printf(MPI_COMM_WORLD,"<PERFTESTS> TpsCpuSolveCOMPOSE = %f \n", temps_cpu);
+      // Compare the two vectors solCOMPOSE and rhs
+      Mpf_printf(MPI_COMM_WORLD, "\n**** Comparing results...\n") ;
+      ierr=computeRelativeError(solCOMPOSE, rhs, relative_error) ; C_CHKERRQ(ierr) ;
+      Mpf_printf(MPI_COMM_WORLD, "<PERFTESTS> Error = %.4e \n", *relative_error);
+    }
+
+    break;
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+template<typename Scalar>
+int testCOMPOSE_BEM(double * relative_error){
+
+  int ierr = 0;
+  double temps_initial, temps_final, temps_cpu;
+  size_t vectorSize = (size_t) nbPts*nbRHS*(complexALGO?2:1);
 
   /* Realise le produit matrice vecteur classique : A.rhs -> solCLA */
 
@@ -67,8 +225,8 @@ int testCOMPOSE_Scalar(double * relative_error){
   (simplePrec ?
    computeDenseBlockFEMBEM_Cprec :
    computeDenseBlockFEMBEM)(&row_min, &row_max, &col_min, &col_max,
-				  &Mpf_i_zero, &Mpf_i_one, &Mpf_i_one, &Mpf_i_one,
-				  &size_of_buffer, &ld, (void *) get_ptr(A), (void *) myCtx.get());
+			    &Mpf_i_zero, &Mpf_i_one, &Mpf_i_one, &Mpf_i_one,
+			    &size_of_buffer, &ld, (void *) get_ptr(A), (void *) myCtx.get());
 
   if(symMatSolver){
     if(symMatContent == 1){
@@ -188,22 +346,44 @@ int testCOMPOSE_Scalar(double * relative_error){
 int testCOMPOSE(double * relative_error){
 
   int ierr = 0;
-  switch(stype) {
-  case (SIMPLE_PRECISION) :
-    ierr = testCOMPOSE_Scalar<float>(relative_error);
-    break ;
-  case (DOUBLE_PRECISION) :
-    ierr = testCOMPOSE_Scalar<double>(relative_error);
-    break ;
-  case (SIMPLE_COMPLEX) :
-    ierr = testCOMPOSE_Scalar<std::complex<float>>(relative_error);
-    break ;
-  case (DOUBLE_COMPLEX) :
-    ierr = testCOMPOSE_Scalar<std::complex<double>>(relative_error);
-    break ;
-  default :
-    C_SETERRQ(1, "testCOMPOSE : unknown scalar type\n") ;
-    break ;
+
+  if(testedModel == _bem){
+    switch(stype) {
+    case (SIMPLE_PRECISION) :
+      ierr = testCOMPOSE_BEM<float>(relative_error);
+      break ;
+    case (DOUBLE_PRECISION) :
+      ierr = testCOMPOSE_BEM<double>(relative_error);
+      break ;
+    case (SIMPLE_COMPLEX) :
+      ierr = testCOMPOSE_BEM<std::complex<float>>(relative_error);
+      break ;
+    case (DOUBLE_COMPLEX) :
+      ierr = testCOMPOSE_BEM<std::complex<double>>(relative_error);
+      break ;
+    default :
+      C_SETERRQ(1, "testCOMPOSE : unknown scalar type\n") ;
+      break ;
+    }
+  }
+  else{ // if(testedModel == _fem)
+    switch(stype) {
+    case (SIMPLE_PRECISION) :
+      ierr = testCOMPOSE_FEM<float>(relative_error);
+      break ;
+    case (DOUBLE_PRECISION) :
+      ierr = testCOMPOSE_FEM<double>(relative_error);
+      break ;
+    case (SIMPLE_COMPLEX) :
+      ierr = testCOMPOSE_FEM<std::complex<float>>(relative_error);
+      break ;
+    case (DOUBLE_COMPLEX) :
+      ierr = testCOMPOSE_FEM<std::complex<double>>(relative_error);
+      break ;
+    default :
+      C_SETERRQ(1, "testCOMPOSE : unknown scalar type\n") ;
+      break ;
+    }
   }
 
   return 0;
-- 
GitLab