text: /******************************************************************************
   * Copyright (c) 1998 Lawrence Livermore National Security, LLC and other
   * HYPRE Project Developers. See the top-level COPYRIGHT file for details.
   *
   * SPDX-License-Identifier: (Apache-2.0 OR MIT)
   ******************************************************************************/
  
  #include "./HYPRE_parcsr_ls.h"
  #include "../matrix_matrix/HYPRE_matrix_matrix_protos.h"
  #include "_hypre_utilities.h"
  
  /* Must include implementation definition for ParVector since no data access
    functions are publically provided. AJC, 5/99 */
  /* Likewise for Vector. AJC, 5/99 */
  #include "../seq_mv/vector.h"
  
  /* AB 8/06 - replace header file */
  /* #include "../parcsr_mv/par_vector.h" */
  #include "../parcsr_mv/_hypre_parcsr_mv.h"
  
  /* These are what we need from Euclid */
  #include "distributed_ls/Euclid/_hypre_Euclid.h"
  /* #include "../distributed_ls/Euclid/Mem_dh.h" */
  /* #include "../distributed_ls/Euclid/io_dh.h" */
  /* #include "../distributed_ls/Euclid/TimeLog_dh.h" */
  /* #include "../distributed_ls/Euclid/Parser_dh.h" */
  /* #include "../distributed_ls/Euclid/Euclid_dh.h" */
  
  /*------------------------------------------------------------------
   * Error checking
   *------------------------------------------------------------------*/
  
  #define HYPRE_EUCLID_ERRCHKA \
            if (errFlag_dh) {  \
              setError_dh("", __FUNC__, __FILE__, __LINE__); \
              printErrorMsg(stderr);  \
              hypre_MPI_Abort(comm_dh, -1); \
            }
  
  /* What is best to do here?
   * What is HYPRE's error checking strategy?
   * The shadow knows . . .
   *
   * Note: HYPRE_EUCLID_ERRCHKA macro is only used within this file.
   *
   * Note: "printErrorMsg(stderr)" is O.K. for debugging and
   *        development, possibly not for production.  This
   *        call causes Euclid to print a function call stack
   *        trace that led to the error.  (Potentially, each
   *        MPI task could print a trace.)
   *
   * Note: the __FUNC__ defines at the beginning of the function
   *       calls are used in Euclid's internal error-checking scheme.
   *       The "START_FUNC_DH" and "END_FUNC_VAL" macros are
   *       used for debugging: when "logFuncsToStderr == true"
   *       a function call trace is force-written to stderr;
   *       (useful for debugging over dial-up lines!)  See
   *       src/distributed_ls/Euclid/macros_dh.h and
   *       src/distributed_ls/Euclid/src/globalObjects.c
   *       for further info.
   */
  
  
  /*--------------------------------------------------------------------------
   * debugging: if ENABLE_EUCLID_LOGGING is defined, each MPI task will open
   * "logFile.id" for writing; also, function-call tracing is operational
   * (ie, you can set logFuncsToFile = true, logFuncsToSterr = true).
   *
   *--------------------------------------------------------------------------*/
  #undef ENABLE_EUCLID_LOGGING
  
  #if !defined(ENABLE_EUCLID_LOGGING)
  #undef START_FUNC_DH
  #undef END_FUNC_VAL
  #undef END_FUNC_DH
  #define START_FUNC_DH     /**/
  #define END_FUNC_DH       /**/
  #define END_FUNC_VAL(a)   return(a);
  #endif
  
  
  /*--------------------------------------------------------------------------
   * HYPRE_EuclidCreate - Return a Euclid "solver".
   *--------------------------------------------------------------------------*/
  
  #undef __FUNC__
  #define __FUNC__ "HYPRE_EuclidCreate"
  HYPRE_Int
  HYPRE_EuclidCreate( MPI_Comm comm,
                      HYPRE_Solver *solver )
  {
  #ifdef HYPRE_MIXEDINT
     hypre_error_w_msg(HYPRE_ERROR_GENERIC, "Euclid cannot be used in mixedint mode!");
     return hypre_error_flag;
  #else
  
     START_FUNC_DH
     Euclid_dh eu;
  
     /*-----------------------------------------------------------
      * create a few global objects (yuck!) for Euclid's use;
      * these  are all pointers, are initially NULL, and are be set
      * back to NULL in HYPRE_EuclidDestroy()
      * Global objects are defined in
      * src/distributed_ls/Euclid/src/globalObjects.c
      *-----------------------------------------------------------*/
  
     comm_dh = comm;
     hypre_MPI_Comm_size(comm_dh, &np_dh);    HYPRE_EUCLID_ERRCHKA;
     hypre_MPI_Comm_rank(comm_dh, &myid_dh);  HYPRE_EUCLID_ERRCHKA;
  
  #ifdef ENABLE_EUCLID_LOGGING
     openLogfile_dh(0, NULL); HYPRE_EUCLID_ERRCHKA;
  #endif
  
     if (mem_dh == NULL)
     {
        Mem_dhCreate(&mem_dh);  HYPRE_EUCLID_ERRCHKA;
     }
  
     if (tlog_dh == NULL)
     {
        TimeLog_dhCreate(&tlog_dh); HYPRE_EUCLID_ERRCHKA;
     }
  
     if (parser_dh == NULL)
     {
        Parser_dhCreate(&parser_dh); HYPRE_EUCLID_ERRCHKA;
     }
     Parser_dhInit(parser_dh, 0, NULL); HYPRE_EUCLID_ERRCHKA;
  
     /*-----------------------------------------------------------
      * create and return a Euclid object
      *-----------------------------------------------------------*/
     Euclid_dhCreate(&eu); HYPRE_EUCLID_ERRCHKA;
     *solver = (HYPRE_Solver) eu;
  
     END_FUNC_VAL(0)
  #endif
  }
  
  /*--------------------------------------------------------------------------
   * HYPRE_EuclidDestroy - Destroy a Euclid object.
   *--------------------------------------------------------------------------*/
  
  #undef __FUNC__
  #define __FUNC__ "HYPRE_EuclidDestroy"
  HYPRE_Int
  HYPRE_EuclidDestroy( HYPRE_Solver solver )
  {
  #ifdef HYPRE_MIXEDINT
     hypre_error_w_msg(HYPRE_ERROR_GENERIC, "Euclid cannot be used in mixedint mode!");
     return hypre_error_flag;
  #else
  
     START_FUNC_DH
     Euclid_dh eu = (Euclid_dh)solver;
     bool printMemReport = false;
     bool printStats = false;
     bool logging = eu->logging;
  
     /*----------------------------------------------------------------
        this block is for printing test data; this is used
        for diffing in autotests.
      *---------------------------------------------------------------- */
     if (Parser_dhHasSwitch(parser_dh, "-printTestData"))
     {
        FILE *fp;
  
        /* get filename to which to write report */
        char fname[] = "test_data_dh.temp", *fnamePtr = fname;
        Parser_dhReadString(parser_dh, "-printTestData", &fnamePtr); HYPRE_EUCLID_ERRCHKA;
        if (!strcmp(fnamePtr, "1"))    /* in case usr didn't supply a name! */
        {
           fnamePtr = fname;
        }
  
        /* print the report */
        fp = openFile_dh(fnamePtr, "w"); HYPRE_EUCLID_ERRCHKA;
        Euclid_dhPrintTestData(eu, fp); HYPRE_EUCLID_ERRCHKA;
        closeFile_dh(fp); HYPRE_EUCLID_ERRCHKA;
  
        printf_dh("\n@@@@@ Euclid test data was printed to file: %s\n\n", fnamePtr);
     }
  
  
     /*----------------------------------------------------------------
        determine which of Euclid's internal reports to print
      *----------------------------------------------------------------*/
     if (logging)
     {
        printStats = true;
        printMemReport = true;
     }
     if (parser_dh != NULL)
     {
        if (Parser_dhHasSwitch(parser_dh, "-eu_stats"))
        {
           printStats = true;
        }
        if (Parser_dhHasSwitch(parser_dh, "-eu_mem"))
        {
           printMemReport = true;
        }
     }
  
     /*------------------------------------------------------------------
        print Euclid's internal report, then destroy the Euclid object
      *------------------------------------------------------------------ */
     if (printStats)
     {
        Euclid_dhPrintHypreReport(eu, stdout); HYPRE_EUCLID_ERRCHKA;
     }
     Euclid_dhDestroy(eu); HYPRE_EUCLID_ERRCHKA;
  
  
     /*------------------------------------------------------------------
        destroy all remaining Euclid library objects
        (except the memory object)
      *------------------------------------------------------------------ */
     /*if (parser_dh != NULL) { dah 3/16/06  */
     if (parser_dh != NULL && ref_counter == 0)
     {
        Parser_dhDestroy(parser_dh); HYPRE_EUCLID_ERRCHKA;
        parser_dh = NULL;
     }
  
     /*if (tlog_dh != NULL) {  dah 3/16/06  */
     if (tlog_dh != NULL && ref_counter == 0)
     {
        TimeLog_dhDestroy(tlog_dh); HYPRE_EUCLID_ERRCHKA;
        tlog_dh = NULL;
     }
  
     /*------------------------------------------------------------------
        optionally print Euclid's memory report,
        then destroy the memory object.
      *------------------------------------------------------------------ */
     /*if (mem_dh != NULL) {  dah 3/16/06  */
     if (mem_dh != NULL && ref_counter == 0)
     {
        if (printMemReport)
        {
           Mem_dhPrint(mem_dh, stdout, false); HYPRE_EUCLID_ERRCHKA;
        }
        Mem_dhDestroy(mem_dh);  HYPRE_EUCLID_ERRCHKA;
        mem_dh = NULL;
     }
  
  #ifdef ENABLE_EUCLID_LOGGING
     closeLogfile_dh(); HYPRE_EUCLID_ERRCHKA;
  #endif
  
     END_FUNC_VAL(0)
  #endif
  }
  
  /*--------------------------------------------------------------------------
   * HYPRE_EuclidSetup - Set up function for Euclid.
   *--------------------------------------------------------------------------*/
  
  #undef __FUNC__
  #define __FUNC__ "HYPRE_EuclidSetup"
  HYPRE_Int
  HYPRE_EuclidSetup( HYPRE_Solver solver,
                     HYPRE_ParCSRMatrix A,
                     HYPRE_ParVector b,
                     HYPRE_ParVector x   )
  {
  #ifdef HYPRE_MIXEDINT
     hypre_error_w_msg(HYPRE_ERROR_GENERIC, "Euclid cannot be used in mixedint mode!");
     return hypre_error_flag;
  #else
  
     START_FUNC_DH
     Euclid_dh eu = (Euclid_dh)solver;
  
  
  #if 0
  
     for testing!
  {
     HYPRE_Int ierr;
     HYPRE_Int m, n, rs, re, cs, ce;
  
     HYPRE_DistributedMatrix mat;
     ierr = HYPRE_ConvertParCSRMatrixToDistributedMatrix( A, &mat );
        if (ierr) { exit(-1); }
  
        ierr = HYPRE_DistributedMatrixGetDims(mat, &m, &n);
        ierr = HYPRE_DistributedMatrixGetLocalRange(mat, &rs, &re,
                                                    &cs, &ce);
  
        hypre_printf("\n### [%i] m= %i, n= %i, rs= %i, re= %i, cs= %i, ce= %i\n",
                     myid_dh, m, n, rs, re, cs, ce);
  
        ierr = HYPRE_DistributedMatrixDestroy(mat);
  
        if (ierr) { exit(-1); }
     }
  #endif
  
     Euclid_dhInputHypreMat(eu, A); HYPRE_EUCLID_ERRCHKA;
     Euclid_dhSetup(eu); HYPRE_EUCLID_ERRCHKA;
  
     END_FUNC_VAL(0)
  #endif
  }
  
  /*--------------------------------------------------------------------------
   * HYPRE_EuclidSolve - Solve function for Euclid.
   *--------------------------------------------------------------------------*/
  
  #undef __FUNC__
  #define __FUNC__ "HYPRE_EuclidSolve"
  HYPRE_Int
  HYPRE_EuclidSolve( HYPRE_Solver solver,
                     HYPRE_ParCSRMatrix A,
                     HYPRE_ParVector bb,
                     HYPRE_ParVector xx  )
  {
  #ifdef HYPRE_MIXEDINT
     hypre_error_w_msg(HYPRE_ERROR_GENERIC, "Euclid cannot be used in mixedint mode!");
     return hypre_error_flag;
  #else
  
     START_FUNC_DH
     Euclid_dh eu = (Euclid_dh)solver;
     HYPRE_Real *b, *x;
  
     x = hypre_VectorData(hypre_ParVectorLocalVector((hypre_ParVector *) bb));
     b = hypre_VectorData(hypre_ParVectorLocalVector((hypre_ParVector *) xx));
  
     Euclid_dhApply(eu, x, b); HYPRE_EUCLID_ERRCHKA;
     END_FUNC_VAL(0)
  #endif
  }
  
  /*--------------------------------------------------------------------------
   * Insert command line (flag, value) pairs in Euclid's
   *--------------------------------------------------------------------------*/
  
  #undef __FUNC__
  #define __FUNC__ "HYPRE_EuclidSetParams"
  HYPRE_Int
  HYPRE_EuclidSetParams(HYPRE_Solver solver,
                        HYPRE_Int argc,
                        char *argv[] )
  {
  #ifdef HYPRE_MIXEDINT
     hypre_error_w_msg(HYPRE_ERROR_GENERIC, "Euclid cannot be used in mixedint mode!");
     return hypre_error_flag;
  #else
     START_FUNC_DH
     Parser_dhInit(parser_dh, argc, argv); HYPRE_EUCLID_ERRCHKA;
  
     /* maintainers note: even though Parser_dhInit() was called in
        HYPRE_EuclidCreate(), it's O.K. to call it again.
      */
     END_FUNC_VAL(0)
  #endif
  }
  
  /*--------------------------------------------------------------------------
   * Insert (flag, value) pairs in Euclid's  database from file
   *--------------------------------------------------------------------------*/
  
  #undef __FUNC__
  #define __FUNC__ "HYPRE_EuclidSetParamsFromFile"
  HYPRE_Int
  HYPRE_EuclidSetParamsFromFile(HYPRE_Solver solver,
                                char *filename )
  {
  #ifdef HYPRE_MIXEDINT
     hypre_error_w_msg(HYPRE_ERROR_GENERIC, "Euclid cannot be used in mixedint mode!");
     return hypre_error_flag;
  #else
  
     START_FUNC_DH
     Parser_dhUpdateFromFile(parser_dh, filename); HYPRE_EUCLID_ERRCHKA;
     END_FUNC_VAL(0)
  #endif
  }
  
  HYPRE_Int
  HYPRE_EuclidSetLevel(HYPRE_Solver solver,
                       HYPRE_Int level)
  {
  #ifdef HYPRE_MIXEDINT
     hypre_error_w_msg(HYPRE_ERROR_GENERIC, "Euclid cannot be used in mixedint mode!");
     return hypre_error_flag;
  #else
  
     char str_level[8];
     START_FUNC_DH
     hypre_sprintf(str_level, "%d", level);
     Parser_dhInsert(parser_dh, "-level", str_level); HYPRE_EUCLID_ERRCHKA;
     END_FUNC_VAL(0)
  #endif
  }
  
  HYPRE_Int
  HYPRE_EuclidSetBJ(HYPRE_Solver solver,
                    HYPRE_Int bj)
  {
  #ifdef HYPRE_MIXEDINT
     hypre_error_w_msg(HYPRE_ERROR_GENERIC, "Euclid cannot be used in mixedint mode!");
     return hypre_error_flag;
  #else
  
     char str_bj[8];
     START_FUNC_DH
     hypre_sprintf(str_bj, "%d", bj);
     Parser_dhInsert(parser_dh, "-bj", str_bj); HYPRE_EUCLID_ERRCHKA;
     END_FUNC_VAL(0)
  #endif
  }
  
  HYPRE_Int
  HYPRE_EuclidSetStats(HYPRE_Solver solver,
                       HYPRE_Int eu_stats)
  {
  #ifdef HYPRE_MIXEDINT
     hypre_error_w_msg(HYPRE_ERROR_GENERIC, "Euclid cannot be used in mixedint mode!");
     return hypre_error_flag;
  #else
  
     char str_eu_stats[8];
     START_FUNC_DH
     hypre_sprintf(str_eu_stats, "%d", eu_stats);
     Parser_dhInsert(parser_dh, "-eu_stats", str_eu_stats); HYPRE_EUCLID_ERRCHKA;
     END_FUNC_VAL(0)
  #endif
  }
  
  HYPRE_Int
  HYPRE_EuclidSetMem(HYPRE_Solver solver,
                     HYPRE_Int eu_mem)
  {
  #ifdef HYPRE_MIXEDINT
     hypre_error_w_msg(HYPRE_ERROR_GENERIC, "Euclid cannot be used in mixedint mode!");
     return hypre_error_flag;
  #else
  
     char str_eu_mem[8];
     START_FUNC_DH
     hypre_sprintf(str_eu_mem, "%d", eu_mem);
     Parser_dhInsert(parser_dh, "-eu_mem", str_eu_mem); HYPRE_EUCLID_ERRCHKA;
     END_FUNC_VAL(0)
  #endif
  }
  
  HYPRE_Int
  HYPRE_EuclidSetSparseA(HYPRE_Solver solver,
                         HYPRE_Real sparse_A)
  {
  #ifdef HYPRE_MIXEDINT
     hypre_error_w_msg(HYPRE_ERROR_GENERIC, "Euclid cannot be used in mixedint mode!");
     return hypre_error_flag;
  #else
  
     char str_sparse_A[256];
     START_FUNC_DH
     hypre_sprintf(str_sparse_A, "%f", sparse_A);
     Parser_dhInsert(parser_dh, "-sparseA", str_sparse_A);
     HYPRE_EUCLID_ERRCHKA;
     END_FUNC_VAL(0)
  #endif
  }
  
  HYPRE_Int
  HYPRE_EuclidSetRowScale(HYPRE_Solver solver,
                          HYPRE_Int row_scale)
  {
  #ifdef HYPRE_MIXEDINT
     hypre_error_w_msg(HYPRE_ERROR_GENERIC, "Euclid cannot be used in mixedint mode!");
     return hypre_error_flag;
  #else
  
     char str_row_scale[8];
     START_FUNC_DH
     hypre_sprintf(str_row_scale, "%d", row_scale);
     Parser_dhInsert(parser_dh, "-rowScale", str_row_scale);
     HYPRE_EUCLID_ERRCHKA;
     END_FUNC_VAL(0)
  #endif
  }
  
  HYPRE_Int
  HYPRE_EuclidSetILUT(HYPRE_Solver solver,
                      HYPRE_Real ilut)
  {
  #ifdef HYPRE_MIXEDINT
     hypre_error_w_msg(HYPRE_ERROR_GENERIC, "Euclid cannot be used in mixedint mode!");
     return hypre_error_flag;
  #else
  
     char str_ilut[256];
     START_FUNC_DH
     hypre_sprintf(str_ilut, "%f", ilut);
     Parser_dhInsert(parser_dh, "-ilut", str_ilut); HYPRE_EUCLID_ERRCHKA;
     END_FUNC_VAL(0)
  #endif
  }
  
  