From 9705cf979962fbf447ed27a3614b271086ce8191 Mon Sep 17 00:00:00 2001 From: Bagaev Dmitri Date: Fri, 30 Sep 2016 13:35:18 +0300 Subject: [PATCH] InnerILU2 added --- Examples/CMakeLists.txt | 17 +- Examples/MatSolve/main.cpp | 67 +- Source/Headers/CMakeLists.txt | 1 + Source/Headers/inmost.h | 1 + Source/Headers/inmost_common.h | 1 + Source/Headers/inmost_solver.h | 539 +-- Source/Headers/inmost_solver_interface.h | 55 + Source/Headers/old_inmost_solver.h | 358 ++ Source/Solver/CMakeLists.txt | 25 +- .../{refactoring => }/SolverFactory.cpp | 3 +- .../Solver/{refactoring => }/SolverFactory.h | 6 +- Source/Solver/old/solver.cpp | 2648 +++++++++++++ Source/Solver/{ => old}/solver_ani.cpp | 0 Source/Solver/{ => old}/solver_ani.h | 0 Source/Solver/{ => old}/solver_bcgsl.hpp | 0 Source/Solver/{ => old}/solver_ddpqiluc2.cpp | 0 Source/Solver/{ => old}/solver_ddpqiluc2.hpp | 0 Source/Solver/{ => old}/solver_fcbiilu2.cpp | 0 Source/Solver/{ => old}/solver_fcbiilu2.h | 0 Source/Solver/{ => old}/solver_ilu2.hpp | 0 Source/Solver/{ => old}/solver_k3biilu2.cpp | 0 Source/Solver/{ => old}/solver_k3biilu2.h | 0 Source/Solver/{ => old}/solver_mtilu2.cpp | 0 Source/Solver/{ => old}/solver_mtilu2.hpp | 0 Source/Solver/{ => old}/solver_mtiluc2.cpp | 0 Source/Solver/{ => old}/solver_mtiluc2.hpp | 0 Source/Solver/{ => old}/solver_petsc.cpp | 0 Source/Solver/{ => old}/solver_petsc.h | 0 Source/Solver/{ => old}/solver_prototypes.hpp | 0 Source/Solver/{ => old}/solver_superlu.cpp | 0 Source/Solver/{ => old}/solver_superlu.h | 0 Source/Solver/old/sparse.cpp | 1260 ++++++ Source/Solver/refactoring/CMakeLists.txt | 18 - Source/Solver/refactoring/Solver2.cpp | 146 - Source/Solver/refactoring/Solver2.h | 67 - Source/Solver/refactoring/SolverInterface.h | 52 - .../refactoring/solver_petsc/CMakeLists.txt | 7 - Source/Solver/solver.cpp | 3437 +++++------------ Source/Solver/solver_inner/CMakeLists.txt | 7 + Source/Solver/solver_inner/solver_bcgsl.hpp | 1868 +++++++++ .../solver_inner/solver_ilu2/CMakeLists.txt | 6 + .../solver_inner/solver_ilu2/SolverILU2.cpp | 145 + .../solver_inner/solver_ilu2/SolverILU2.h | 58 + .../solver_inner/solver_ilu2/solver_ilu2.hpp | 530 +++ .../Solver/solver_inner/solver_prototypes.hpp | 39 + Source/Solver/solver_petsc/CMakeLists.txt | 7 + .../solver_petsc/SolverPETSc.cpp | 24 +- .../solver_petsc/SolverPETSc.h | 15 +- .../solver_petsc.cpp} | 72 +- .../solver_petsc.h} | 8 +- 50 files changed, 8151 insertions(+), 3336 deletions(-) create mode 100644 Source/Headers/inmost_solver_interface.h create mode 100644 Source/Headers/old_inmost_solver.h rename Source/Solver/{refactoring => }/SolverFactory.cpp (97%) rename Source/Solver/{refactoring => }/SolverFactory.h (93%) create mode 100644 Source/Solver/old/solver.cpp rename Source/Solver/{ => old}/solver_ani.cpp (100%) rename Source/Solver/{ => old}/solver_ani.h (100%) rename Source/Solver/{ => old}/solver_bcgsl.hpp (100%) rename Source/Solver/{ => old}/solver_ddpqiluc2.cpp (100%) rename Source/Solver/{ => old}/solver_ddpqiluc2.hpp (100%) rename Source/Solver/{ => old}/solver_fcbiilu2.cpp (100%) rename Source/Solver/{ => old}/solver_fcbiilu2.h (100%) rename Source/Solver/{ => old}/solver_ilu2.hpp (100%) rename Source/Solver/{ => old}/solver_k3biilu2.cpp (100%) rename Source/Solver/{ => old}/solver_k3biilu2.h (100%) rename Source/Solver/{ => old}/solver_mtilu2.cpp (100%) rename Source/Solver/{ => old}/solver_mtilu2.hpp (100%) rename Source/Solver/{ => old}/solver_mtiluc2.cpp (100%) rename Source/Solver/{ => old}/solver_mtiluc2.hpp (100%) rename Source/Solver/{ => old}/solver_petsc.cpp (100%) rename Source/Solver/{ => old}/solver_petsc.h (100%) rename Source/Solver/{ => old}/solver_prototypes.hpp (100%) rename Source/Solver/{ => old}/solver_superlu.cpp (100%) rename Source/Solver/{ => old}/solver_superlu.h (100%) create mode 100644 Source/Solver/old/sparse.cpp delete mode 100644 Source/Solver/refactoring/CMakeLists.txt delete mode 100644 Source/Solver/refactoring/Solver2.cpp delete mode 100644 Source/Solver/refactoring/Solver2.h delete mode 100644 Source/Solver/refactoring/SolverInterface.h delete mode 100644 Source/Solver/refactoring/solver_petsc/CMakeLists.txt create mode 100644 Source/Solver/solver_inner/CMakeLists.txt create mode 100644 Source/Solver/solver_inner/solver_bcgsl.hpp create mode 100644 Source/Solver/solver_inner/solver_ilu2/CMakeLists.txt create mode 100644 Source/Solver/solver_inner/solver_ilu2/SolverILU2.cpp create mode 100644 Source/Solver/solver_inner/solver_ilu2/SolverILU2.h create mode 100644 Source/Solver/solver_inner/solver_ilu2/solver_ilu2.hpp create mode 100644 Source/Solver/solver_inner/solver_prototypes.hpp create mode 100644 Source/Solver/solver_petsc/CMakeLists.txt rename Source/Solver/{refactoring => }/solver_petsc/SolverPETSc.cpp (93%) rename Source/Solver/{refactoring => }/solver_petsc/SolverPETSc.h (85%) rename Source/Solver/{refactoring/solver_petsc/new_solver_petsc.cpp => solver_petsc/solver_petsc.cpp} (91%) rename Source/Solver/{refactoring/solver_petsc/new_solver_petsc.h => solver_petsc/solver_petsc.h} (91%) diff --git a/Examples/CMakeLists.txt b/Examples/CMakeLists.txt index be23b6b..86e7021 100644 --- a/Examples/CMakeLists.txt +++ b/Examples/CMakeLists.txt @@ -1,18 +1,21 @@ +#Actually Solver class in refactoring state right now +#All examples will be refactored too after the main stage + if(USE_MESH) #add_subdirectory(DrawGrid) -add_subdirectory(OldDrawGrid) -add_subdirectory(GridGen) +#add_subdirectory(OldDrawGrid) +#add_subdirectory(GridGen) endif(USE_MESH) if(USE_SOLVER) -add_subdirectory(DrawMatrix) +#add_subdirectory(DrawMatrix) add_subdirectory(MatSolve) endif(USE_SOLVER) if(USE_SOLVER AND USE_MESH) -add_subdirectory(FVDiscr) -add_subdirectory(Solver) +#add_subdirectory(FVDiscr) +#add_subdirectory(Solver) endif(USE_SOLVER AND USE_MESH) if(USE_AUTODIFF AND USE_SOLVER AND USE_MESH) -add_subdirectory(ADFVDiscr) -add_subdirectory(ADMFD) +#add_subdirectory(ADFVDiscr) +#add_subdirectory(ADMFD) endif(USE_AUTODIFF AND USE_SOLVER AND USE_MESH) #add_subdirectory(OctreeCutcell) \ No newline at end of file diff --git a/Examples/MatSolve/main.cpp b/Examples/MatSolve/main.cpp index 28777fe..931bc2a 100644 --- a/Examples/MatSolve/main.cpp +++ b/Examples/MatSolve/main.cpp @@ -5,7 +5,6 @@ #include #include "inmost.h" -#include "Source/Solver/refactoring/Solver2.h" #include "inner_parser.h" using namespace INMOST; @@ -33,7 +32,7 @@ int main(int argc, char ** argv) { std::string vectorBFileName = ""; std::string vectorXFileName = ""; std::string parametersFileName = ""; - int solverType = 0; + std::string solverName = ""; bool matrixFound = false; bool vectorBFound = false; @@ -57,21 +56,7 @@ int main(int argc, char ** argv) { std::cout << "-b, --bvector " << std::endl; std::cout << "-x, --xvector " << std::endl; std::cout << "-p, --parameters " << std::endl; - std::cout << "-t, --type " << std::endl; - std::cout << " 0: INNER_ILU2 " << std::endl; - std::cout << " 1: INNER_DDPQILUC " << std::endl; - std::cout << " 2: INNER_MPTILUC " << std::endl; - std::cout << " 3: INNER_MPTILU2 " << std::endl; - std::cout << " 4: Trilinos_Aztec " << std::endl; - std::cout << " 5: Trilinos_Belos " << std::endl; - std::cout << " 6: Trilinos_ML " << std::endl; - std::cout << " 7: Trilinos_Ifpack " << std::endl; - std::cout << " 8: PETSc " << std::endl; - std::cout << " 9: ANI " << std::endl; - std::cout << " 10: FCBIILU2 " << std::endl; - std::cout << " 11: K3BIILU2 " << std::endl; - std::cout << " 12: SUPERLU " << std::endl << std::endl; - std::cout << "-h, --help - print this message." << std::endl; + std::cout << "-t, --type " << std::endl; } #if defined(USE_MPI) MPI_Finalize(); @@ -133,7 +118,7 @@ int main(int argc, char ** argv) { std::cout << "Solver type index found: " << argv[i + 1] << std::endl; } typeFound = true; - solverType = atoi(argv[i + 1]); + solverName = std::string(argv[i + 1]); i++; continue; } @@ -163,39 +148,13 @@ int main(int argc, char ** argv) { } } - - Solver::Type type; - switch (solverType) { - case 0: type = Solver::INNER_ILU2; break; - case 1: type = Solver::INNER_DDPQILUC; break; - case 2: type = Solver::INNER_MPTILUC; break; - case 3: type = Solver::INNER_MPTILU2; break; - case 4: type = Solver::Trilinos_Aztec; break; - case 5: type = Solver::Trilinos_Belos; break; - case 6: type = Solver::Trilinos_ML; break; - case 7: type = Solver::Trilinos_Ifpack; break; - case 8: type = Solver::PETSc; break; - case 9: type = Solver::ANI; break; - case 10: type = Solver::FCBIILU2; break; - case 11: type = Solver::K3BIILU2; break; - case 12: type = Solver::SUPERLU; break; - default: - if (processRank == 0) { - std::cout << "Invalid solver type index: " << solverType << " , using INNER_ILU2 instead." << - std::endl; - } - type = Solver::INNER_ILU2; - break; - } - // Initialize the linear solver in accordance with args - Solver2::Initialize(&argc, &argv, parametersFound ? parametersFileName.c_str() : NULL); - Solver2 solver = Solver2("petsc"); - Solver2 solver2 = solver; + Solver::Initialize(&argc, &argv, parametersFound ? parametersFileName.c_str() : NULL); + Solver solver = Solver(solverName); //solver2.Finalize(); if (processRank == 0) { - std::cout << "Solving with " << Solver::TypeName(type) << std::endl; + std::cout << "Solving with " << solverName << std::endl; } Sparse::Matrix mat("A"); // Declare the matrix of the linear system to be solved @@ -267,18 +226,18 @@ int main(int argc, char ** argv) { tempTimer = Timer(); - solver2.SetMatrix(mat); + solver.SetMatrix(mat); //s.SetMatrix(mat); // Compute the preconditioner for the original matrix BARRIER if (processRank == 0) std::cout << "preconditioner time: " << Timer() - tempTimer << std::endl; tempTimer = Timer(); - success = solver2.Solve(b, x); // Solve the linear system with the previously computted preconditioner + success = solver.Solve(b, x); // Solve the linear system with the previously computted preconditioner BARRIER solvingTimer = Timer() - solvingTimer; if (processRank == 0) std::cout << "iterations time: " << Timer() - tempTimer << std::endl; - iters = solver2.Iterations(); // Get the number of iterations performed - resid = solver2.Residual(); // Get the final residual achieved - reason = solver2.ReturnReason(); // Get the convergence reason + iters = solver.Iterations(); // Get the number of iterations performed + resid = solver.Residual(); // Get the final residual achieved + reason = solver.ReturnReason(); // Get the convergence reason //x.Save("output.sol"); // Save the solution if required // Compute the true residual @@ -309,7 +268,7 @@ int main(int argc, char ** argv) { std::cout << "||Ax-b||=" << sqrt(recv[0]) << " ||b||=" << sqrt(recv[1]) << " ||Ax-b||/||b||=" << sqrt(recv[0] / (recv[1] + 1.0e-100)) << std::endl; std::cout << "norms: " << Timer() - tempTimer << std::endl; - std::cout << processorsCount << " processors for Solver::type=" << type; + std::cout << processorsCount << " processors for Solver " << solverName; if (success) { std::cout << " solved in " << solvingTimer << " secs"; std::cout << " with " << iters << " iterations to " << resid << " norm"; @@ -362,6 +321,6 @@ int main(int argc, char ** argv) { } } BARRIER - Solver2::Finalize(); // Finalize solver and close MPI activity + Solver::Finalize(); // Finalize solver and close MPI activity return 0; } diff --git a/Source/Headers/CMakeLists.txt b/Source/Headers/CMakeLists.txt index f4dce92..87401ba 100644 --- a/Source/Headers/CMakeLists.txt +++ b/Source/Headers/CMakeLists.txt @@ -12,6 +12,7 @@ set(HEADER ${CMAKE_CURRENT_SOURCE_DIR}/inmost_dense.h ${CMAKE_CURRENT_SOURCE_DIR}/inmost_mesh.h ${CMAKE_CURRENT_SOURCE_DIR}/inmost_solver.h + ${CMAKE_CURRENT_SOURCE_DIR}/inmost_solver_interface.h ${CMAKE_CURRENT_SOURCE_DIR}/inmost_partitioner.h ${CMAKE_CURRENT_SOURCE_DIR}/inmost_autodiff.h ${CMAKE_CURRENT_SOURCE_DIR}/inmost_expression.h diff --git a/Source/Headers/inmost.h b/Source/Headers/inmost.h index e5fc253..321b485 100644 --- a/Source/Headers/inmost.h +++ b/Source/Headers/inmost.h @@ -6,6 +6,7 @@ #include "inmost_mesh.h" #include "inmost_dense.h" #include "inmost_solver.h" +#include "inmost_solver_interface.h" #include "inmost_partitioner.h" #include "inmost_variable.h" #include "inmost_nonlinear.h" diff --git a/Source/Headers/inmost_common.h b/Source/Headers/inmost_common.h index 9f7110a..c3325de 100644 --- a/Source/Headers/inmost_common.h +++ b/Source/Headers/inmost_common.h @@ -222,6 +222,7 @@ namespace INMOST PrepareMatrixFirst, CannotReusePreconditionerOfDifferentSize, SolverNotFound, + SolverUnsupportedOperation, /// The list of errors may occur in the Partitioner. ErrorInPartitioner = 500, diff --git a/Source/Headers/inmost_solver.h b/Source/Headers/inmost_solver.h index 93230b6..a205628 100644 --- a/Source/Headers/inmost_solver.h +++ b/Source/Headers/inmost_solver.h @@ -1,12 +1,13 @@ +// +// Created by Dmitri Bagaev on 22.09.16. +// #ifndef INMOST_SOLVER_INCLUDED #define INMOST_SOLVER_INCLUDED - +#include "inmost_solver_interface.h" #include "inmost_common.h" #include "inmost_sparse.h" -//#include "solver_prototypes.hpp" - #define DEFAULT_ADDITIVE_SCHWARTZ_OVERLAP 1 #define DEFAULT_ABSOLUTE_TOLERANCE 1.0e-5 @@ -24,335 +25,209 @@ #define DEFAULT_PRECONDITIONER_ADAPT_DDPQ_TOLERANCE 1 #if defined(USE_SOLVER) -namespace INMOST -{ - /// Main class to set and solve linear system. - /// Solver class is used to set the coefficient Matrix, the right-hand side Vector - /// and the initial guess Vector, construct the preconditioner and Solve - /// the linear system. - /// - /// Formally, Solver class is independent of INMOST::Mesh class. - /// @see Sparse::Matrix - /// @see Sparse::Vector - /// @see Sparse::Solve - class Solver - { - private: - static INMOST_MPI_Type RowEntryType; //prepared in Initialize - public: - /// Type of the Solver can be currently used in this version of INMOST. - enum Type - { - INNER_ILU2, ///< inner Solver based on BiCGStab(L) solver with second order ILU factorization as preconditioner. - INNER_DDPQILUC, ///< inner Solver based on BiCGStab(L) solver with second order Crout-ILU with inversed-based condition estimation and unsymmetric reordering for diagonal dominance as preconditioner. - INNER_MPTILUC, ///< inner Solver based on BiCGStab(L) solver with second order Crout-ILU with inversed-based condition estimation and maximum product transversal reordering as preconditioner. - INNER_MPTILU2, ///< inner Solver based on BiCGStab(L) solver with second order ILU and maximum product transversal reordering as preconditioner. - Trilinos_Aztec, ///< external Solver AztecOO from Trilinos package. - Trilinos_Belos, ///< external Solver Belos from Trilinos package, currently without preconditioner. - Trilinos_ML, ///< external Solver AztecOO with ML preconditioner. - Trilinos_Ifpack,///< external Solver AztecOO with Ifpack preconditioner. - PETSc, ///< external Solver PETSc, @see http://www.mcs.anl.gov/petsc/ - ANI, ///< external Solver from ANI3D based on ILU2 (sequential Fortran version), @see http://ani3d.sourceforge.net/ - FCBIILU2, ///< external FCBIILU2 Solver (BIILU2 parallel F2C version). - K3BIILU2, ///< inner K3BIILU2 Solver (BIILU2 parallel version). - SUPERLU ///< external Solver SuperLU @see https://github.com/starseeker/SuperLU - }; - - static std::string TypeName(Type t); - - - //solver.cpp:::::::::::::::::::::::::::::::::::::::::::::::::::: - public: - - /// Base class for low level operations with objects of Solver class. - class OrderInfo - { - private: - typedef std::vector storage_type; - storage_type global_to_proc; //stores ends of all non-overlapping intervals of elements, owned by this processor - storage_type global_overlap; //stores pairs: [begin,end) of overlapping intervals of rows - std::vector vector_exchange_recv, vector_exchange_send; - std::vector send_storage, recv_storage; - std::vector send_requests, recv_requests; - std::vector extended_indexes; - - //remote indexes - INMOST_DATA_ENUM_TYPE local_vector_begin, local_vector_end; - INMOST_DATA_ENUM_TYPE initial_matrix_begin, initial_matrix_end; //local interval of matrix - INMOST_DATA_ENUM_TYPE local_matrix_begin, local_matrix_end; //local interval of matrix - - bool have_matrix; - INMOST_MPI_Comm comm; - int rank,size; - public: - void Clear(); - /// Return true if Matrix data have already been specified. - bool & HaveMatrix() { return have_matrix; } - OrderInfo(); - OrderInfo(const OrderInfo & other); - OrderInfo & operator =(OrderInfo const & other); - ~OrderInfo(); - /// Prepare parallel state of the Matrix with specified overlap size. - /// This state of the matrix can be used, for instance, to construct - /// the preconditioner for Additive Swartz method. - /// @param m Matrix to be expanded. - /// @param overlap Overlap size, viz. the number of overlap layers. - void PrepareMatrix(Sparse::Matrix & m, INMOST_DATA_ENUM_TYPE overlap); - /// Restore initial nonparallel state of the Matrix with no overlap. - void RestoreMatrix(Sparse::Matrix & m); - /// Prepare parallel state of the Vector. - void PrepareVector(Sparse::Vector & v) const; - /// Restore initial nonparallel state of the Vector. - void RestoreVector(Sparse::Vector & v) const; - /// Retrieve the processor number by binary search for the specified global index. - INMOST_DATA_ENUM_TYPE GetProcessor(INMOST_DATA_ENUM_TYPE gind) const; //retrieve processor by binary search in global_to_proc - void GetOverlapRegion(INMOST_DATA_ENUM_TYPE proc, INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const; - /// Get the local index region for the specified process. - void GetLocalRegion(INMOST_DATA_ENUM_TYPE proc, INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const; - /// Get the local index region for the current process. - void GetVectorRegion(INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const {mbeg = local_vector_begin; mend = local_vector_end;} - /// Get the rank of the current communicator, i.e. the current process index. - INMOST_DATA_ENUM_TYPE GetRank() const {return rank;} - /// Get the size of the current communicator, i.e. the total number of processes used. - INMOST_DATA_ENUM_TYPE GetSize() const {return size;} - /// Update the shared data in parallel vector. - void Update (Sparse::Vector & x); // update parallel vector - /// Sum shared values in parallel vector. - void Accumulate(Sparse::Vector & x); // sum shared values in parallel vector - /// Get the sum of num elements of real array on all processes. - void Integrate(INMOST_DATA_REAL_TYPE * inout, INMOST_DATA_ENUM_TYPE num) const; - /// Get the communicator which the solver is associated with. - INMOST_MPI_Comm GetComm() const {return comm;} - // Access to arrays below allows to organize manual exchange - INMOST_MPI_Request * GetSendRequests() {assert(!send_requests.empty()); return &send_requests[0];} - INMOST_MPI_Request * GetRecvRequests() {assert(!recv_requests.empty()); return &recv_requests[0];} - INMOST_DATA_ENUM_TYPE GetSendRequestsSize() {return static_cast(send_requests.size());} - INMOST_DATA_ENUM_TYPE GetRecvRequestsSize() {return static_cast(recv_requests.size());} - INMOST_DATA_ENUM_TYPE * GetSendExchangeArray() {assert(!vector_exchange_send.empty()); return &vector_exchange_send[0];} - INMOST_DATA_ENUM_TYPE GetSendExchangeSize() {return static_cast(send_storage.size());} - INMOST_DATA_ENUM_TYPE * GetRecvExchangeArray() {assert(!vector_exchange_recv.empty()); return &vector_exchange_recv[0];} - INMOST_DATA_ENUM_TYPE GetRecvExchangeSize() {return static_cast(recv_storage.size());} - //for debug - //~ void BeginSequentialCode() {for(int i = 0; i < rank; i++) MPI_Barrier(comm);} - //~ void EndSequentialCode() {for(int i = rank; i < size; i++) MPI_Barrier(comm);} - - // Get the scalar product of the specified interval of the distributed vector. - // Conflicts with OpenMP, should not be used in future - //void ScalarProd(Vector const & left, Vector const & right, INMOST_DATA_ENUM_TYPE index_begin, INMOST_DATA_ENUM_TYPE index_end, INMOST_DATA_REAL_TYPE & sum) const; - }; - - - - private: - static bool is_initialized, is_finalized; - INMOST_MPI_Comm comm; - std::string name; - INMOST_DATA_ENUM_TYPE local_size, global_size; - INMOST_DATA_ENUM_TYPE last_it; - INMOST_DATA_REAL_TYPE last_resid; - OrderInfo info; - - INMOST_DATA_ENUM_TYPE additive_schwartz_overlap; - - INMOST_DATA_ENUM_TYPE maximum_iterations; - INMOST_DATA_REAL_TYPE absolute_tolerance; - INMOST_DATA_REAL_TYPE relative_tolerance; - INMOST_DATA_REAL_TYPE divergence_tolerance; - - INMOST_DATA_REAL_TYPE preconditioner_drop_tolerance; - INMOST_DATA_REAL_TYPE preconditioner_reuse_tolerance; - INMOST_DATA_REAL_TYPE preconditioner_ddpq_tolerance; - INMOST_DATA_ENUM_TYPE preconditioner_reorder_nonzero; - INMOST_DATA_REAL_TYPE preconditioner_fill_level; - INMOST_DATA_ENUM_TYPE preconditioner_rescale_iterations; - INMOST_DATA_ENUM_TYPE preconditioner_condition_estimation; - INMOST_DATA_ENUM_TYPE preconditioner_adapt_ddpq_tolerance; - - INMOST_DATA_ENUM_TYPE solver_gmres_substeps; - - std::string return_reason; - - void * solver_data; - void * matrix_data; - void * precond_data; - - void * rhs_data; - void * solution_data; - - Type _pack; - Solver(const Solver & other);// prohibit copy - Solver & operator =(Solver const & other); //prohibit assignment - public: - /// Retrive approximate condition number produced by INNER_MPTILUC. - /// The number is cond(L^-1). - INMOST_DATA_REAL_TYPE GetConditionNumberL(); - /// Retrive approximate condition number produced by INNER_MPTILUC. - /// The number is cond(U^-1). - INMOST_DATA_REAL_TYPE GetConditionNumberU(); - /// Set the solver parameter of the integer type. - /// You can find defaults for parameters in the top of the file inmost_solver.h. - /// - /// Parameters: - /// - "maximum_iterations" - total number of iterations - /// - "schwartz_overlap" - number of overlapping levels for additive schwartz method, - /// works for: - /// INNER_ILU2, INNER_MLILUC - /// Trilinos_Aztec, Trilinos_Belos, Trilinos_ML, Trilinos_Ifpack - /// PETSc - /// - "gmres_substeps" - number of gmres steps performed after each bicgstab step, - /// works for: - /// INNER_ILU2, INNER_MLILUC - /// - "reorder_nonzeros" - place sparser rows at the beggining of matrix during reordering, - /// works for: - /// INNER_MLILUC - /// - "rescale_iterations" - number of iterations for two-side matrix rescaling, - /// works for: - /// INNER_ILU2, INNER_MLILUC - /// - "condition_estimation" - exploit condition estimation of inversed factors to adapt - /// drop and reuse tolerances, - /// works for: - /// INNER_MLILUC - /// - "adapt_ddpq_tolerance" - adapt ddpq tolerance depending from the complexity - /// of calculation of Schur complement, - /// works for: - /// INNER_MLILUC - void SetParameterEnum(std::string name, INMOST_DATA_ENUM_TYPE value); - /// Set the solver parameter of the real type. - /// You can find defaults for parameters in the top of the file inmost_solver.h. - /// - /// Parameters: - /// - "absolute_tolerance" - iterative method will stop on i-th iteration - /// if ||A x(i)-b|| < absolute_tolerance - /// - "relative_tolerance" - iterative method will stop on i-th iteration - /// if ||A x(i)-b||/||A x(0) - b|| - /// - "divergence_tolerance" - iterative method will fail if - /// ||A x(i) - b|| > divergence_tolerance - /// - "drop_tolerance" - tolerance for dropping values during incomplete factorization, - /// works for: - /// INNER_ILU2, INNER_MLILUC - /// Trilinos_Aztec, Trilinos_Ifpack - /// PETSc - /// - "reuse_tolerance" - tolerance for reusing values during incomplete factorization, - /// these values are used only during calculation of L and U factors - /// and/or Schur complement and discarded once factorization is done, - /// value should be less then "drop_tolerance", - /// typical value is drop_tolerance^2, - /// works for: - /// INNER_ILU2, INNER_MLILUC - /// - "ddpq_tolerance" - by this tolerance most diagonnaly-dominant elements will be selected - /// to form the next level of factorization, the closer the tolerance - /// is to one the smaller will be the level. Actual rule is: - /// A(i,j)/(sum(A(i,:))+sum(A(:,j))-A(i,j)) > ddpq_tolerance * - /// A(imax,jmax)/(sum(A(imax,:))+sum(A(:,jmax))-A(imax,jmax)) - /// where on imax, jmax maximum is reached. - /// works for: - /// INNER_MLILUC - /// - "fill_level" - level of fill for ILU-type preconditioners, - /// works for: - /// INNER_ILU2 (if LFILL is defined in solver_ilu2.hpp) - /// Trilinos, Trilinos_Ifpack - void SetParameterReal(std::string name, INMOST_DATA_REAL_TYPE value); - /// Get the used defined name of the Solver. - std::string GetName() {return name;} - /// Get the package Type. - Type GetPackage() const {return _pack;} - /// Set the matrix and construct the preconditioner. - /// @param A Matrix A in linear problem Ax = b - /// @param ModifiedPattern Indicates whether the structure of the matrix have - /// changed since last call to Solver::SetMatrix. - /// @param OldPreconditioner If this parameter is set to true, - /// then the previous preconditioner will be used, - /// otherwise the new preconditioner will be constructed. - /// - /// Preconditioner will be constructed on call to this function - /// - for INNER_*, PETSc and ANI packages - /// - for Trilinos preconditioner will be constructed each time Sparse::Solve is called - /// - /// Any changes to preconditioner parameters should happen before that point. - /// If you increase gmres_substep after this point, inner methods most likely will fail - void SetMatrix(Sparse::Matrix & A, bool ModifiedPattern = true, bool OldPreconditioner = false); - /// Solver the linear system: A*x = b. - /// Prior to this call you should call SetMatrix - /// - /// @param RHS The right-hand side Vector b. - /// @param SOL The initial guess to the solution on input and the solution Vector x on return. - /// - /// It is assumed that the coefficient matrix A have been set - /// and the preconditioner have been already constructed. - /// - /// @see Sparse::SetMatrix - bool Solve(Sparse::Vector & RHS, Sparse::Vector & SOL); - /// Return the number of iterations performed by the last solution. - /// @see Sparse::Solve - INMOST_DATA_ENUM_TYPE Iterations(); - /// Return the final residual achieved by the last solution. - /// @see Sparse::Solve - INMOST_DATA_REAL_TYPE Residual(); - /// Get the reason of convergence or divergence of the last solution. - /// @see Sparse::Solve - std::string GetReason(); - /// Computes the smallest and the largest eigenvalue with the power method. - /// Requires SetMatrix to be called to compute the preconditioner. - /// Currently works for internal methods only, since it uses internal matrix-vector multiplication. - /// Largest eigenvalue: vprev = 0; v = rand(); while( |v|-|vprev| > tol ) {vprev = v; v = A*v; v /= |v|;} - /// lambda_max = |v|; - /// Smallest eigenvalue: vprev = 0; v = rand(); while( |v|-|vprev| > tol ){vprev = v; solve(A*v = v); v /= |v|;} - /// lambda_min = 1.0/|v|; - /// See answer by Blair Perot in: - /// https://www.researchgate.net/post/What_is_the_best_way_to_estimate_the_condition_number_of_a_sparse_matrix. - /// @param tol Tolerance used for power series. - /// @param maxits Maximum number of iterations allowed. - /// @return Condition number or 1.0e100 if not converged. - INMOST_DATA_REAL_TYPE Condest(INMOST_DATA_REAL_TYPE tol, INMOST_DATA_ENUM_TYPE maxits = 100); - /// Main constructor of the solver. - /// Solver name provided here is used to extract options from database file - /// for PETSc and Trilinos packages. - /// @param pack The package Type to be used for solution. - /// @param _name The user specified name of the current solver. - /// @param comm Communicator for parallel data exchanges, MPI_COMM_WORLD by default. - /// @see Solver::Initialize - /// @see Solver::SetMatrix - /// @see Solver::Solve - /// @see Solver::Finalize - Solver(Type pack, std::string _name = "", INMOST_MPI_Comm comm = INMOST_MPI_COMM_WORLD); - ~Solver(); - /// Initialize the stage of parallel solution. - /// If MPI is not initialized yet, then it will be initialized. - /// - /// database file is used to pass parameters to PETSc and Trilinos packages. - /// if database file for is provided any changes through SetParameterEnum, - /// SetParameterReal would not be effective for PETSc and Trilinos packages. - /// Currently this database file provides directions for package-specific - /// files. In future it is supposed to set up parameters for internal solvers. - /// @param argc The number of arguments transmitted to the function main. - /// @param argv The pointer to arguments transmitted to the function main. - /// @param database Usually the name of the file with the Solver parameters. - /// - /// The shortest call to this function with the default solver parameters is the following: Initialize(NULL,NULL,""); - /// @see Solver::Finalize - /// @see Solver::isInitialized - /// - /// Example of contents of the database file: - /// - /// PETSc: petsc_options.txt - /// Trilinos_Ifpack: trilinos_ifpack_options.xml - /// Trilinos_ML: trilinos_ml_options.xml - /// Trilinos_Aztec: trilinos_aztec_options.xml - /// Trilinos_Belos: trilinos_belos_options.xml - static void Initialize(int * argc, char *** argv, const char * database = ""); - /// Finalize the stage of parallel solution. - /// If MPI was initialized in Solver::Initialize, then it will be finalized. - /// By this reason, do not use any MPI function after call to this function. - /// @see Solver::Initialize - /// @see Solver::isFinalized - static void Finalize(); - static bool isInitialized() {return is_initialized;} - static bool isFinalized() {return is_finalized;} - /// Clear all internal data of the current solver including matrix, preconditioner etc. - void Clear(); - }; +namespace INMOST { + +#define GUARD_MPI(x) {ierr = x; if( ierr != MPI_SUCCESS ) {char str[4096]; int len; MPI_Error_string(ierr,str,&len); std::cout << #x << " not successfull: " << str << std::endl; MPI_Abort(comm,-1000);}} +#define HASH_TABLE_SIZE 2048 + + class Solver { + private: + static int *argc; + static char ***argv; + static const char *database; + static bool is_initialized; + static bool is_finalized; + + //Actual solver using for solving system + SolverInterface *solver; + std::string prefix; + public: + + /// Base class for low level operations with objects of Solver class. + class OrderInfo + { + private: + typedef std::vector storage_type; + storage_type global_to_proc; //stores ends of all non-overlapping intervals of elements, owned by this processor + storage_type global_overlap; //stores pairs: [begin,end) of overlapping intervals of rows + std::vector vector_exchange_recv, vector_exchange_send; + std::vector send_storage, recv_storage; + std::vector send_requests, recv_requests; + std::vector extended_indexes; + + //remote indexes + INMOST_DATA_ENUM_TYPE local_vector_begin, local_vector_end; + INMOST_DATA_ENUM_TYPE initial_matrix_begin, initial_matrix_end; //local interval of matrix + INMOST_DATA_ENUM_TYPE local_matrix_begin, local_matrix_end; //local interval of matrix + + bool have_matrix; + INMOST_MPI_Comm comm; + int rank,size; + public: + void Clear(); + /// Return true if Matrix data have already been specified. + bool & HaveMatrix() { return have_matrix; } + OrderInfo(); + OrderInfo(const OrderInfo & other); + OrderInfo & operator =(OrderInfo const & other); + ~OrderInfo(); + /// Prepare parallel state of the Matrix with specified overlap size. + /// This state of the matrix can be used, for instance, to construct + /// the preconditioner for Additive Swartz method. + /// @param m Matrix to be expanded. + /// @param overlap Overlap size, viz. the number of overlap layers. + void PrepareMatrix(Sparse::Matrix & m, INMOST_DATA_ENUM_TYPE overlap); + /// Restore initial nonparallel state of the Matrix with no overlap. + void RestoreMatrix(Sparse::Matrix & m); + /// Prepare parallel state of the Vector. + void PrepareVector(Sparse::Vector & v) const; + /// Restore initial nonparallel state of the Vector. + void RestoreVector(Sparse::Vector & v) const; + /// Retrieve the processor number by binary search for the specified global index. + INMOST_DATA_ENUM_TYPE GetProcessor(INMOST_DATA_ENUM_TYPE gind) const; //retrieve processor by binary search in global_to_proc + void GetOverlapRegion(INMOST_DATA_ENUM_TYPE proc, INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const; + /// Get the local index region for the specified process. + void GetLocalRegion(INMOST_DATA_ENUM_TYPE proc, INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const; + /// Get the local index region for the current process. + void GetVectorRegion(INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const {mbeg = local_vector_begin; mend = local_vector_end;} + /// Get the rank of the current communicator, i.e. the current process index. + INMOST_DATA_ENUM_TYPE GetRank() const {return rank;} + /// Get the size of the current communicator, i.e. the total number of processes used. + INMOST_DATA_ENUM_TYPE GetSize() const {return size;} + /// Update the shared data in parallel vector. + void Update (Sparse::Vector & x); // update parallel vector + /// Sum shared values in parallel vector. + void Accumulate(Sparse::Vector & x); // sum shared values in parallel vector + /// Get the sum of num elements of real array on all processes. + void Integrate(INMOST_DATA_REAL_TYPE * inout, INMOST_DATA_ENUM_TYPE num) const; + /// Get the communicator which the solver is associated with. + INMOST_MPI_Comm GetComm() const {return comm;} + // Access to arrays below allows to organize manual exchange + INMOST_MPI_Request * GetSendRequests() {assert(!send_requests.empty()); return &send_requests[0];} + INMOST_MPI_Request * GetRecvRequests() {assert(!recv_requests.empty()); return &recv_requests[0];} + INMOST_DATA_ENUM_TYPE GetSendRequestsSize() {return static_cast(send_requests.size());} + INMOST_DATA_ENUM_TYPE GetRecvRequestsSize() {return static_cast(recv_requests.size());} + INMOST_DATA_ENUM_TYPE * GetSendExchangeArray() {assert(!vector_exchange_send.empty()); return &vector_exchange_send[0];} + INMOST_DATA_ENUM_TYPE GetSendExchangeSize() {return static_cast(send_storage.size());} + INMOST_DATA_ENUM_TYPE * GetRecvExchangeArray() {assert(!vector_exchange_recv.empty()); return &vector_exchange_recv[0];} + INMOST_DATA_ENUM_TYPE GetRecvExchangeSize() {return static_cast(recv_storage.size());} + //for debug + //~ void BeginSequentialCode() {for(int i = 0; i < rank; i++) MPI_Barrier(comm);} + //~ void EndSequentialCode() {for(int i = rank; i < size; i++) MPI_Barrier(comm);} + + // Get the scalar product of the specified interval of the distributed vector. + // Conflicts with OpenMP, should not be used in future + //void ScalarProd(Vector const & left, Vector const & right, INMOST_DATA_ENUM_TYPE index_begin, INMOST_DATA_ENUM_TYPE index_end, INMOST_DATA_REAL_TYPE & sum) const; + }; + + // Main constructor of the solver. + /// @param solverName The solver name to be used for solution. + /// @param prefix The user specified name of the current solver. + /// @param comm Communicator for parallel data exchanges, MPI_COMM_WORLD by default. + /// @see Solver::Initialize + /// @see Solver::SetMatrix + /// @see Solver::Solve + /// @see Solver::Finalize + Solver(std::string solverName, std::string prefix = "", INMOST_MPI_Comm _comm = INMOST_MPI_COMM_WORLD); + + Solver(const Solver& other); + Solver& operator =(const Solver& other); + + /// Return the solver name + /// @see Sparse::Solve + std::string SolverName() const; + /// Return the solver user specified name of the current solver + /// @see Sparse::Solve + std::string SolverPrefix() const; + + /// Initialize the stage of parallel solution. + /// If MPI is not initialized yet, then it will be initialized. + /// + /// database file is used to pass parameters to PETSc and Trilinos packages. + /// if database file for is provided any changes through SetParameterEnum, + /// SetParameterReal would not be effective for PETSc and Trilinos packages. + /// Currently this database file provides directions for package-specific + /// files. In future it is supposed to set up parameters for internal solvers. + /// @param argc The number of arguments transmitted to the function main. + /// @param argv The pointer to arguments transmitted to the function main. + /// @param database Usually the name of the file with the Solver parameters. + /// + /// The shortest call to this function with the default solver parameters is the following: Initialize(NULL,NULL,""); + /// @see Solver::Finalize + /// @see Solver::isInitialized + /// + /// Example of contents of the database file: + /// + /// PETSc: petsc_options.txt + /// Trilinos_Ifpack: trilinos_ifpack_options.xml + /// Trilinos_ML: trilinos_ml_options.xml + /// Trilinos_Aztec: trilinos_aztec_options.xml + /// Trilinos_Belos: trilinos_belos_options.xml + static void Initialize(int *argc, char ***argv, const char *database); + + /// Finalize the stage of parallel solution. + /// If MPI was initialized in Solver::Initialize, then it will be finalized. + /// By this reason, do not use any MPI function after call to this function. + /// @see Solver::Initialize + /// @see Solver::isFinalized + static void Finalize(); + + static bool isInitialized(); + static bool isFinalized(); + + /// Set the matrix and construct the preconditioner. + /// @param A Matrix A in linear problem Ax = b + /// @param ModifiedPattern Indicates whether the structure of the matrix have + /// changed since last call to Solver::SetMatrix. + /// @param OldPreconditioner If this parameter is set to true, + /// then the previous preconditioner will be used, + /// otherwise the new preconditioner will be constructed. + /// + /// Preconditioner will be constructed on call to this function + /// - for INNER_*, PETSc and ANI packages + /// - for Trilinos preconditioner will be constructed each time Sparse::Solve is called + /// + /// Any changes to preconditioner parameters should happen before that point. + /// If you increase gmres_substep after this point, inner methods most likely will fail + void SetMatrix(Sparse::Matrix & A, bool ModifiedPattern = true, bool OldPreconditioner = false); + + /// Solver the linear system: A*x = b. + /// Prior to this call you should call SetMatrix + /// + /// @param RHS The right-hand side Vector b. + /// @param SOL The initial guess to the solution on input and the solution Vector x on return. + /// + /// It is assumed that the coefficient matrix A have been set + /// and the preconditioner have been already constructed. + /// + /// @see Sparse::SetMatrix + bool Solve(INMOST::Sparse::Vector & RHS, INMOST::Sparse::Vector & SOL); + + /// Clear all internal data of the current solver including matrix, preconditioner etc. + bool Clear(); + + INMOST_DATA_REAL_TYPE GetPropertyReal(std::string property) const; + INMOST_DATA_ENUM_TYPE GetPropertyEnum(std::string property) const; + + void SetPropertyReal(std::string property, INMOST_DATA_REAL_TYPE value); + void SetPropertyEnum(std::string property, INMOST_DATA_ENUM_TYPE value); + + /// Return the number of iterations performed by the last solution. + /// @see Sparse::Solve + const INMOST_DATA_ENUM_TYPE Iterations() const; + /// Return the final residual achieved by the last solution. + /// @see Sparse::Solve + const INMOST_DATA_REAL_TYPE Residual() const; + /// Get the reason of convergence or divergence of the last solution. + /// @see Sparse::Solve + const std::string ReturnReason() const; + + ~Solver(); +private: + static std::string parseDatabase(std::string solverName); + }; } -#endif // USE_SOLVER +#endif -#endif // INMOST_SOLVER_INCLUDED +#endif //INMOST_SOLVER_INCLUDED diff --git a/Source/Headers/inmost_solver_interface.h b/Source/Headers/inmost_solver_interface.h new file mode 100644 index 0000000..4213bd5 --- /dev/null +++ b/Source/Headers/inmost_solver_interface.h @@ -0,0 +1,55 @@ +#ifndef INMOST_SOLVERINTERFACE_H +#define INMOST_SOLVERINTERFACE_H + +#include +#include "inmost_sparse.h" + +namespace INMOST { + +#if defined(USE_SOLVER) + + class SolverInterface { + protected: + INMOST_MPI_Comm communicator; + public: + SolverInterface() {}; + SolverInterface(const SolverInterface* other) {}; + virtual void Assign(const SolverInterface* other) = 0; + + virtual void Initialize(int *argc, char ***argv, const char *parameters_file, std::string prefix) = 0; + virtual void SetMatrix(Sparse::Matrix & A, bool ModifiedPattern, bool OldPreconditioner) = 0; + virtual bool Solve(INMOST::Sparse::Vector & RHS, INMOST::Sparse::Vector & SOL) = 0; + virtual bool Clear() = 0; + + virtual bool isMatrixSet() = 0; + + virtual INMOST_DATA_REAL_TYPE GetPropertyReal(std::string property) const = 0; + virtual INMOST_DATA_ENUM_TYPE GetPropertyEnum(std::string property) const = 0; + + virtual void SetPropertyReal(std::string property, INMOST_DATA_REAL_TYPE value) = 0; + virtual void SetPropertyEnum(std::string property, INMOST_DATA_ENUM_TYPE value) = 0; + + virtual const INMOST_DATA_ENUM_TYPE Iterations() const = 0; + virtual const INMOST_DATA_REAL_TYPE Residual() const = 0; + virtual const std::string ReturnReason() const = 0; + + virtual const std::string SolverName() const = 0; + + virtual void Finalize() = 0; + virtual ~SolverInterface() {}; + + + void SetCommunicator(INMOST_MPI_Comm _communicator) { + communicator = _communicator; + } + + INMOST_MPI_Comm GetCommunicator() { + return communicator; + } + }; + +} +#endif + + +#endif //INMOST_SOLVERINTERFACE_H diff --git a/Source/Headers/old_inmost_solver.h b/Source/Headers/old_inmost_solver.h new file mode 100644 index 0000000..93230b6 --- /dev/null +++ b/Source/Headers/old_inmost_solver.h @@ -0,0 +1,358 @@ + +#ifndef INMOST_SOLVER_INCLUDED +#define INMOST_SOLVER_INCLUDED + + +#include "inmost_common.h" +#include "inmost_sparse.h" +//#include "solver_prototypes.hpp" + + +#define DEFAULT_ADDITIVE_SCHWARTZ_OVERLAP 1 +#define DEFAULT_ABSOLUTE_TOLERANCE 1.0e-5 +#define DEFAULT_RELATIVE_TOLERANCE 1.0e-12 +#define DEFAULT_DIVERGENCE_TOLERANCE 1.0e+100 +#define DEFAULT_MAXIMUM_ITERATIONS 2500 +#define DEFAULT_SOLVER_GMRES_SUBSTEPS 2 +#define DEFAULT_PRECONDITIONER_DROP_TOLERANCE 0.005 +#define DEFAULT_PRECONDITIONER_REUSE_TOLERANCE 0.00005 +#define DEFAULT_PRECONDITIONER_FILL_LEVEL 3 +#define DEFAULT_PRECONDITIONER_DDPQ_TOLERANCE 0.75 +#define DEFAULT_PRECONDITIONER_REORDER_NONZEROS 1 +#define DEFAULT_PRECONDITIONER_RESCALE_ITERS 6 +#define DEFAULT_PRECONDITIONER_CONDITION_ESTIMATION 1 +#define DEFAULT_PRECONDITIONER_ADAPT_DDPQ_TOLERANCE 1 + +#if defined(USE_SOLVER) +namespace INMOST +{ + /// Main class to set and solve linear system. + /// Solver class is used to set the coefficient Matrix, the right-hand side Vector + /// and the initial guess Vector, construct the preconditioner and Solve + /// the linear system. + /// + /// Formally, Solver class is independent of INMOST::Mesh class. + /// @see Sparse::Matrix + /// @see Sparse::Vector + /// @see Sparse::Solve + class Solver + { + private: + static INMOST_MPI_Type RowEntryType; //prepared in Initialize + public: + /// Type of the Solver can be currently used in this version of INMOST. + enum Type + { + INNER_ILU2, ///< inner Solver based on BiCGStab(L) solver with second order ILU factorization as preconditioner. + INNER_DDPQILUC, ///< inner Solver based on BiCGStab(L) solver with second order Crout-ILU with inversed-based condition estimation and unsymmetric reordering for diagonal dominance as preconditioner. + INNER_MPTILUC, ///< inner Solver based on BiCGStab(L) solver with second order Crout-ILU with inversed-based condition estimation and maximum product transversal reordering as preconditioner. + INNER_MPTILU2, ///< inner Solver based on BiCGStab(L) solver with second order ILU and maximum product transversal reordering as preconditioner. + Trilinos_Aztec, ///< external Solver AztecOO from Trilinos package. + Trilinos_Belos, ///< external Solver Belos from Trilinos package, currently without preconditioner. + Trilinos_ML, ///< external Solver AztecOO with ML preconditioner. + Trilinos_Ifpack,///< external Solver AztecOO with Ifpack preconditioner. + PETSc, ///< external Solver PETSc, @see http://www.mcs.anl.gov/petsc/ + ANI, ///< external Solver from ANI3D based on ILU2 (sequential Fortran version), @see http://ani3d.sourceforge.net/ + FCBIILU2, ///< external FCBIILU2 Solver (BIILU2 parallel F2C version). + K3BIILU2, ///< inner K3BIILU2 Solver (BIILU2 parallel version). + SUPERLU ///< external Solver SuperLU @see https://github.com/starseeker/SuperLU + }; + + static std::string TypeName(Type t); + + + //solver.cpp:::::::::::::::::::::::::::::::::::::::::::::::::::: + public: + + /// Base class for low level operations with objects of Solver class. + class OrderInfo + { + private: + typedef std::vector storage_type; + storage_type global_to_proc; //stores ends of all non-overlapping intervals of elements, owned by this processor + storage_type global_overlap; //stores pairs: [begin,end) of overlapping intervals of rows + std::vector vector_exchange_recv, vector_exchange_send; + std::vector send_storage, recv_storage; + std::vector send_requests, recv_requests; + std::vector extended_indexes; + + //remote indexes + INMOST_DATA_ENUM_TYPE local_vector_begin, local_vector_end; + INMOST_DATA_ENUM_TYPE initial_matrix_begin, initial_matrix_end; //local interval of matrix + INMOST_DATA_ENUM_TYPE local_matrix_begin, local_matrix_end; //local interval of matrix + + bool have_matrix; + INMOST_MPI_Comm comm; + int rank,size; + public: + void Clear(); + /// Return true if Matrix data have already been specified. + bool & HaveMatrix() { return have_matrix; } + OrderInfo(); + OrderInfo(const OrderInfo & other); + OrderInfo & operator =(OrderInfo const & other); + ~OrderInfo(); + /// Prepare parallel state of the Matrix with specified overlap size. + /// This state of the matrix can be used, for instance, to construct + /// the preconditioner for Additive Swartz method. + /// @param m Matrix to be expanded. + /// @param overlap Overlap size, viz. the number of overlap layers. + void PrepareMatrix(Sparse::Matrix & m, INMOST_DATA_ENUM_TYPE overlap); + /// Restore initial nonparallel state of the Matrix with no overlap. + void RestoreMatrix(Sparse::Matrix & m); + /// Prepare parallel state of the Vector. + void PrepareVector(Sparse::Vector & v) const; + /// Restore initial nonparallel state of the Vector. + void RestoreVector(Sparse::Vector & v) const; + /// Retrieve the processor number by binary search for the specified global index. + INMOST_DATA_ENUM_TYPE GetProcessor(INMOST_DATA_ENUM_TYPE gind) const; //retrieve processor by binary search in global_to_proc + void GetOverlapRegion(INMOST_DATA_ENUM_TYPE proc, INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const; + /// Get the local index region for the specified process. + void GetLocalRegion(INMOST_DATA_ENUM_TYPE proc, INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const; + /// Get the local index region for the current process. + void GetVectorRegion(INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const {mbeg = local_vector_begin; mend = local_vector_end;} + /// Get the rank of the current communicator, i.e. the current process index. + INMOST_DATA_ENUM_TYPE GetRank() const {return rank;} + /// Get the size of the current communicator, i.e. the total number of processes used. + INMOST_DATA_ENUM_TYPE GetSize() const {return size;} + /// Update the shared data in parallel vector. + void Update (Sparse::Vector & x); // update parallel vector + /// Sum shared values in parallel vector. + void Accumulate(Sparse::Vector & x); // sum shared values in parallel vector + /// Get the sum of num elements of real array on all processes. + void Integrate(INMOST_DATA_REAL_TYPE * inout, INMOST_DATA_ENUM_TYPE num) const; + /// Get the communicator which the solver is associated with. + INMOST_MPI_Comm GetComm() const {return comm;} + // Access to arrays below allows to organize manual exchange + INMOST_MPI_Request * GetSendRequests() {assert(!send_requests.empty()); return &send_requests[0];} + INMOST_MPI_Request * GetRecvRequests() {assert(!recv_requests.empty()); return &recv_requests[0];} + INMOST_DATA_ENUM_TYPE GetSendRequestsSize() {return static_cast(send_requests.size());} + INMOST_DATA_ENUM_TYPE GetRecvRequestsSize() {return static_cast(recv_requests.size());} + INMOST_DATA_ENUM_TYPE * GetSendExchangeArray() {assert(!vector_exchange_send.empty()); return &vector_exchange_send[0];} + INMOST_DATA_ENUM_TYPE GetSendExchangeSize() {return static_cast(send_storage.size());} + INMOST_DATA_ENUM_TYPE * GetRecvExchangeArray() {assert(!vector_exchange_recv.empty()); return &vector_exchange_recv[0];} + INMOST_DATA_ENUM_TYPE GetRecvExchangeSize() {return static_cast(recv_storage.size());} + //for debug + //~ void BeginSequentialCode() {for(int i = 0; i < rank; i++) MPI_Barrier(comm);} + //~ void EndSequentialCode() {for(int i = rank; i < size; i++) MPI_Barrier(comm);} + + // Get the scalar product of the specified interval of the distributed vector. + // Conflicts with OpenMP, should not be used in future + //void ScalarProd(Vector const & left, Vector const & right, INMOST_DATA_ENUM_TYPE index_begin, INMOST_DATA_ENUM_TYPE index_end, INMOST_DATA_REAL_TYPE & sum) const; + }; + + + + private: + static bool is_initialized, is_finalized; + INMOST_MPI_Comm comm; + std::string name; + INMOST_DATA_ENUM_TYPE local_size, global_size; + INMOST_DATA_ENUM_TYPE last_it; + INMOST_DATA_REAL_TYPE last_resid; + OrderInfo info; + + INMOST_DATA_ENUM_TYPE additive_schwartz_overlap; + + INMOST_DATA_ENUM_TYPE maximum_iterations; + INMOST_DATA_REAL_TYPE absolute_tolerance; + INMOST_DATA_REAL_TYPE relative_tolerance; + INMOST_DATA_REAL_TYPE divergence_tolerance; + + INMOST_DATA_REAL_TYPE preconditioner_drop_tolerance; + INMOST_DATA_REAL_TYPE preconditioner_reuse_tolerance; + INMOST_DATA_REAL_TYPE preconditioner_ddpq_tolerance; + INMOST_DATA_ENUM_TYPE preconditioner_reorder_nonzero; + INMOST_DATA_REAL_TYPE preconditioner_fill_level; + INMOST_DATA_ENUM_TYPE preconditioner_rescale_iterations; + INMOST_DATA_ENUM_TYPE preconditioner_condition_estimation; + INMOST_DATA_ENUM_TYPE preconditioner_adapt_ddpq_tolerance; + + INMOST_DATA_ENUM_TYPE solver_gmres_substeps; + + std::string return_reason; + + void * solver_data; + void * matrix_data; + void * precond_data; + + void * rhs_data; + void * solution_data; + + Type _pack; + Solver(const Solver & other);// prohibit copy + Solver & operator =(Solver const & other); //prohibit assignment + public: + /// Retrive approximate condition number produced by INNER_MPTILUC. + /// The number is cond(L^-1). + INMOST_DATA_REAL_TYPE GetConditionNumberL(); + /// Retrive approximate condition number produced by INNER_MPTILUC. + /// The number is cond(U^-1). + INMOST_DATA_REAL_TYPE GetConditionNumberU(); + /// Set the solver parameter of the integer type. + /// You can find defaults for parameters in the top of the file inmost_solver.h. + /// + /// Parameters: + /// - "maximum_iterations" - total number of iterations + /// - "schwartz_overlap" - number of overlapping levels for additive schwartz method, + /// works for: + /// INNER_ILU2, INNER_MLILUC + /// Trilinos_Aztec, Trilinos_Belos, Trilinos_ML, Trilinos_Ifpack + /// PETSc + /// - "gmres_substeps" - number of gmres steps performed after each bicgstab step, + /// works for: + /// INNER_ILU2, INNER_MLILUC + /// - "reorder_nonzeros" - place sparser rows at the beggining of matrix during reordering, + /// works for: + /// INNER_MLILUC + /// - "rescale_iterations" - number of iterations for two-side matrix rescaling, + /// works for: + /// INNER_ILU2, INNER_MLILUC + /// - "condition_estimation" - exploit condition estimation of inversed factors to adapt + /// drop and reuse tolerances, + /// works for: + /// INNER_MLILUC + /// - "adapt_ddpq_tolerance" - adapt ddpq tolerance depending from the complexity + /// of calculation of Schur complement, + /// works for: + /// INNER_MLILUC + void SetParameterEnum(std::string name, INMOST_DATA_ENUM_TYPE value); + /// Set the solver parameter of the real type. + /// You can find defaults for parameters in the top of the file inmost_solver.h. + /// + /// Parameters: + /// - "absolute_tolerance" - iterative method will stop on i-th iteration + /// if ||A x(i)-b|| < absolute_tolerance + /// - "relative_tolerance" - iterative method will stop on i-th iteration + /// if ||A x(i)-b||/||A x(0) - b|| + /// - "divergence_tolerance" - iterative method will fail if + /// ||A x(i) - b|| > divergence_tolerance + /// - "drop_tolerance" - tolerance for dropping values during incomplete factorization, + /// works for: + /// INNER_ILU2, INNER_MLILUC + /// Trilinos_Aztec, Trilinos_Ifpack + /// PETSc + /// - "reuse_tolerance" - tolerance for reusing values during incomplete factorization, + /// these values are used only during calculation of L and U factors + /// and/or Schur complement and discarded once factorization is done, + /// value should be less then "drop_tolerance", + /// typical value is drop_tolerance^2, + /// works for: + /// INNER_ILU2, INNER_MLILUC + /// - "ddpq_tolerance" - by this tolerance most diagonnaly-dominant elements will be selected + /// to form the next level of factorization, the closer the tolerance + /// is to one the smaller will be the level. Actual rule is: + /// A(i,j)/(sum(A(i,:))+sum(A(:,j))-A(i,j)) > ddpq_tolerance * + /// A(imax,jmax)/(sum(A(imax,:))+sum(A(:,jmax))-A(imax,jmax)) + /// where on imax, jmax maximum is reached. + /// works for: + /// INNER_MLILUC + /// - "fill_level" - level of fill for ILU-type preconditioners, + /// works for: + /// INNER_ILU2 (if LFILL is defined in solver_ilu2.hpp) + /// Trilinos, Trilinos_Ifpack + void SetParameterReal(std::string name, INMOST_DATA_REAL_TYPE value); + /// Get the used defined name of the Solver. + std::string GetName() {return name;} + /// Get the package Type. + Type GetPackage() const {return _pack;} + /// Set the matrix and construct the preconditioner. + /// @param A Matrix A in linear problem Ax = b + /// @param ModifiedPattern Indicates whether the structure of the matrix have + /// changed since last call to Solver::SetMatrix. + /// @param OldPreconditioner If this parameter is set to true, + /// then the previous preconditioner will be used, + /// otherwise the new preconditioner will be constructed. + /// + /// Preconditioner will be constructed on call to this function + /// - for INNER_*, PETSc and ANI packages + /// - for Trilinos preconditioner will be constructed each time Sparse::Solve is called + /// + /// Any changes to preconditioner parameters should happen before that point. + /// If you increase gmres_substep after this point, inner methods most likely will fail + void SetMatrix(Sparse::Matrix & A, bool ModifiedPattern = true, bool OldPreconditioner = false); + /// Solver the linear system: A*x = b. + /// Prior to this call you should call SetMatrix + /// + /// @param RHS The right-hand side Vector b. + /// @param SOL The initial guess to the solution on input and the solution Vector x on return. + /// + /// It is assumed that the coefficient matrix A have been set + /// and the preconditioner have been already constructed. + /// + /// @see Sparse::SetMatrix + bool Solve(Sparse::Vector & RHS, Sparse::Vector & SOL); + /// Return the number of iterations performed by the last solution. + /// @see Sparse::Solve + INMOST_DATA_ENUM_TYPE Iterations(); + /// Return the final residual achieved by the last solution. + /// @see Sparse::Solve + INMOST_DATA_REAL_TYPE Residual(); + /// Get the reason of convergence or divergence of the last solution. + /// @see Sparse::Solve + std::string GetReason(); + /// Computes the smallest and the largest eigenvalue with the power method. + /// Requires SetMatrix to be called to compute the preconditioner. + /// Currently works for internal methods only, since it uses internal matrix-vector multiplication. + /// Largest eigenvalue: vprev = 0; v = rand(); while( |v|-|vprev| > tol ) {vprev = v; v = A*v; v /= |v|;} + /// lambda_max = |v|; + /// Smallest eigenvalue: vprev = 0; v = rand(); while( |v|-|vprev| > tol ){vprev = v; solve(A*v = v); v /= |v|;} + /// lambda_min = 1.0/|v|; + /// See answer by Blair Perot in: + /// https://www.researchgate.net/post/What_is_the_best_way_to_estimate_the_condition_number_of_a_sparse_matrix. + /// @param tol Tolerance used for power series. + /// @param maxits Maximum number of iterations allowed. + /// @return Condition number or 1.0e100 if not converged. + INMOST_DATA_REAL_TYPE Condest(INMOST_DATA_REAL_TYPE tol, INMOST_DATA_ENUM_TYPE maxits = 100); + /// Main constructor of the solver. + /// Solver name provided here is used to extract options from database file + /// for PETSc and Trilinos packages. + /// @param pack The package Type to be used for solution. + /// @param _name The user specified name of the current solver. + /// @param comm Communicator for parallel data exchanges, MPI_COMM_WORLD by default. + /// @see Solver::Initialize + /// @see Solver::SetMatrix + /// @see Solver::Solve + /// @see Solver::Finalize + Solver(Type pack, std::string _name = "", INMOST_MPI_Comm comm = INMOST_MPI_COMM_WORLD); + ~Solver(); + /// Initialize the stage of parallel solution. + /// If MPI is not initialized yet, then it will be initialized. + /// + /// database file is used to pass parameters to PETSc and Trilinos packages. + /// if database file for is provided any changes through SetParameterEnum, + /// SetParameterReal would not be effective for PETSc and Trilinos packages. + /// Currently this database file provides directions for package-specific + /// files. In future it is supposed to set up parameters for internal solvers. + /// @param argc The number of arguments transmitted to the function main. + /// @param argv The pointer to arguments transmitted to the function main. + /// @param database Usually the name of the file with the Solver parameters. + /// + /// The shortest call to this function with the default solver parameters is the following: Initialize(NULL,NULL,""); + /// @see Solver::Finalize + /// @see Solver::isInitialized + /// + /// Example of contents of the database file: + /// + /// PETSc: petsc_options.txt + /// Trilinos_Ifpack: trilinos_ifpack_options.xml + /// Trilinos_ML: trilinos_ml_options.xml + /// Trilinos_Aztec: trilinos_aztec_options.xml + /// Trilinos_Belos: trilinos_belos_options.xml + static void Initialize(int * argc, char *** argv, const char * database = ""); + /// Finalize the stage of parallel solution. + /// If MPI was initialized in Solver::Initialize, then it will be finalized. + /// By this reason, do not use any MPI function after call to this function. + /// @see Solver::Initialize + /// @see Solver::isFinalized + static void Finalize(); + static bool isInitialized() {return is_initialized;} + static bool isFinalized() {return is_finalized;} + /// Clear all internal data of the current solver including matrix, preconditioner etc. + void Clear(); + }; +} + +#endif // USE_SOLVER + +#endif // INMOST_SOLVER_INCLUDED diff --git a/Source/Solver/CMakeLists.txt b/Source/Solver/CMakeLists.txt index 46975de..4355a73 100644 --- a/Source/Solver/CMakeLists.txt +++ b/Source/Solver/CMakeLists.txt @@ -1,26 +1,23 @@ -add_subdirectory(refactoring) - set(SOURCE ${SOURCE} - ${CMAKE_CURRENT_SOURCE_DIR}/solver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Solver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/SolverFactory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sparse.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/solver_ani.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/solver_ddpqiluc2.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/solver_petsc.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/solver_superlu.cpp ) set(HEADER ${HEADER} - ${CMAKE_CURRENT_SOURCE_DIR}/solver_prototypes.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/solver_petsc.h - ${CMAKE_CURRENT_SOURCE_DIR}/solver_superlu.h - ${CMAKE_CURRENT_SOURCE_DIR}/solver_ilu2.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/solver_ddpqiluc2.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/solver_bcgsl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/solver_ani.h + ${CMAKE_CURRENT_SOURCE_DIR}/SolverFactory.h ) +add_subdirectory(solver_inner) + +if(USE_SOLVER_PETSC) + add_subdirectory(solver_petsc) +endif() + + + if( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/solver_mtiluc2.hpp" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/solver_mtiluc2.cpp" ) set(SOLVER_DEFINITIONS ${SOLVER_DEFINITIONS} -DHAVE_SOLVER_MPTILUC2) diff --git a/Source/Solver/refactoring/SolverFactory.cpp b/Source/Solver/SolverFactory.cpp similarity index 97% rename from Source/Solver/refactoring/SolverFactory.cpp rename to Source/Solver/SolverFactory.cpp index 245c5ab..33673eb 100644 --- a/Source/Solver/refactoring/SolverFactory.cpp +++ b/Source/Solver/SolverFactory.cpp @@ -2,8 +2,9 @@ // Created by Dmitri Bagaev on 28.09.16. // +#include "inmost.h" #include "SolverFactory.h" -#include "SolverInterface.h" + namespace INMOST { diff --git a/Source/Solver/refactoring/SolverFactory.h b/Source/Solver/SolverFactory.h similarity index 93% rename from Source/Solver/refactoring/SolverFactory.h rename to Source/Solver/SolverFactory.h index 83e72a8..4d8bf72 100644 --- a/Source/Solver/refactoring/SolverFactory.h +++ b/Source/Solver/SolverFactory.h @@ -1,11 +1,7 @@ -// -// Created by Dmitri Bagaev on 28.09.16. -// - #ifndef INMOST_SOLVERFACTORY_H #define INMOST_SOLVERFACTORY_H -#include "SolverInterface.h" +#include namespace INMOST { diff --git a/Source/Solver/old/solver.cpp b/Source/Solver/old/solver.cpp new file mode 100644 index 0000000..c0fbeeb --- /dev/null +++ b/Source/Solver/old/solver.cpp @@ -0,0 +1,2648 @@ +#define _CRT_SECURE_NO_WARNINGS +#include "inmost_solver.h" +#if defined(USE_SOLVER) +#include "solver_petsc.h" +#include "solver_superlu.h" +#include "solver_ani.h" +#include "solver_ilu2.hpp" +#include "solver_ddpqiluc2.hpp" +#if defined(HAVE_SOLVER_MPTILUC2) +#include "solver_mtiluc2.hpp" +#endif +#if defined(HAVE_SOLVER_MPTILU2) +#include "solver_mtilu2.hpp" +#endif +#if defined(HAVE_SOLVER_FCBIILU2) +#include "solver_fcbiilu2.h" +#endif +#if defined(HAVE_SOLVER_K3BIILU2) +#include "solver_k3biilu2.h" +#endif +#include "solver_bcgsl.hpp" +#include +#include +#include + +#if defined(USE_SOLVER_TRILINOS) +#if defined(USE_MPI) +#include "Epetra_MpiComm.h" +#else +#include "Epetra_SerialComm.h" +#endif +#include "Epetra_Map.h" +#include "Epetra_Vector.h" +#include "Epetra_CrsMatrix.h" +#include "AztecOO.h" +#include "Ifpack.h" +#include "ml_include.h" +#include "ml_MultiLevelPreconditioner.h" +#include "BelosEpetraOperator.h" +#include "Teuchos_Comm.hpp" +#include "Teuchos_DefaultMpiComm.hpp" +#include "Teuchos_OpaqueWrapper.hpp" +#include "Teuchos_ParameterList.hpp" +#include "Teuchos_TestForException.hpp" +#include "Teuchos_XMLParameterListHelpers.hpp" +#endif +//#define USE_OMP + +//#define KSOLVER BCGSL_solver +#define KSOLVER BCGS_solver +//#define ACCELERATED_CONDEST +//#define PRINT_CONDEST + +namespace INMOST +{ + static std::string petsc_database_file = ""; + static std::string trilinos_aztec_database_file = ""; + static std::string trilinos_ifpack_database_file = ""; + static std::string trilinos_belos_database_file = ""; + static std::string trilinos_ml_database_file = ""; + static std::string ani_database_file = ""; + static std::string fcbiilu2_database_file = ""; + static std::string k3biilu2_database_file = ""; + static std::string superlu_database_file = ""; + + + +#define GUARD_MPI(x) {ierr = x; if( ierr != MPI_SUCCESS ) {char str[4096]; int len; MPI_Error_string(ierr,str,&len); std::cout << #x << " not successfull: " << str << std::endl; MPI_Abort(comm,-1000);}} +#define HASH_TABLE_SIZE 2048 + + bool Solver::is_initialized = false; + bool Solver::is_finalized = false; + + std::string Solver::TypeName(Type t) + { + switch(t) + { + case INNER_ILU2: return "INNER_ILU2"; + case INNER_DDPQILUC: return "INNER_DDPQILUC"; + case INNER_MPTILUC: return "INNER_MPTILUC"; + case INNER_MPTILU2: return "INNER_MPTILU2"; + case Trilinos_Aztec: return "Trilinos_Aztec"; + case Trilinos_Belos: return "Trilinos_Belos"; + case Trilinos_ML: return "Trilinos_ML"; + case Trilinos_Ifpack: return "Trilinos_Ifpack"; + case PETSc: return "PETSc"; + case ANI: return "ANI"; + case FCBIILU2: return "FCBIILU2"; + case K3BIILU2: return "K3BIILU2"; + case SUPERLU: return "SUPERLU"; + } + return "Unknown"; + } + + int comparator(const void * pa, const void *pb) + { + INMOST_DATA_ENUM_TYPE * a = (INMOST_DATA_ENUM_TYPE *)pa, * b = (INMOST_DATA_ENUM_TYPE *)pb; + return a[0] - b[0]; + } + + INMOST_DATA_ENUM_TYPE binary_search_pairs(INMOST_DATA_ENUM_TYPE * link, INMOST_DATA_ENUM_TYPE size, INMOST_DATA_ENUM_TYPE find) + { + INMOST_DATA_ENUM_TYPE rcur = size >> 1, lcur = 0, mid, chk; + while( rcur >= lcur ) + { + mid = lcur + ((rcur-lcur) >> 1); + chk = mid << 1; + if( link[chk] < find ) lcur = mid+1; + else if( link[chk] > find ) rcur = mid-1; + else return chk; + } + return size; + } + void Solver::OrderInfo::Integrate(INMOST_DATA_REAL_TYPE * inout, INMOST_DATA_ENUM_TYPE num) const + { +#if defined(USE_MPI) + if( GetSize() == 1 ) return; +#if defined(USE_OMP) +#pragma omp single +#endif + { + int ierr = 0; + dynarray temp(num); + memcpy(temp.data(),inout,sizeof(INMOST_DATA_REAL_TYPE)*num); + GUARD_MPI(MPI_Allreduce(temp.data(),inout,num,INMOST_MPI_DATA_REAL_TYPE,MPI_SUM,comm)); + } +#else + (void) inout; + (void) num; +#endif + } + + + void Solver::OrderInfo::PrepareMatrix(Sparse::Matrix & m, INMOST_DATA_ENUM_TYPE overlap) + { + have_matrix = true; + m.isParallel() = true; + INMOST_DATA_ENUM_TYPE two[2]; + INMOST_DATA_ENUM_TYPE mbeg,mend; + int initial_rank; +#if defined(USE_MPI) + int ierr = 0; + if( comm != INMOST_MPI_COMM_WORLD ) + { + MPI_Comm_free(&comm); + comm = INMOST_MPI_COMM_WORLD; + } + if( m.GetCommunicator() == INMOST_MPI_COMM_WORLD ) + comm = INMOST_MPI_COMM_WORLD; + else MPI_Comm_dup(m.GetCommunicator(), &comm); + MPI_Comm_rank(comm,&rank); + MPI_Comm_size(comm,&size); +#else + (void) overlap; + rank = 0; + size = 1; +#endif + initial_rank = rank; + //std::vector requests; + global_overlap.resize(size*2); + global_to_proc.resize(size+1); + m.GetInterval(mbeg,mend); + global_to_proc[0] = 0; + initial_matrix_begin = mbeg; + initial_matrix_end = mend; + two[0] = mbeg; + two[1] = mend; +#if defined(USE_MPI) + GUARD_MPI(MPI_Allgather(two,2,INMOST_MPI_DATA_ENUM_TYPE,&global_overlap[0],2,INMOST_MPI_DATA_ENUM_TYPE,comm)); +#else + local_vector_begin = initial_matrix_begin = local_matrix_begin = global_overlap[0] = mbeg; + local_vector_end = initial_matrix_end = local_matrix_end = global_overlap[1] = mend; + global_to_proc[1] = mend; +#endif +#if defined(USE_MPI) + //reorder processors if needed + { + //starts of local indexes should appear in asscending order + bool reorder = false; + for(int k = 0; k < size-1; k++) + if( global_overlap[2*k] > global_overlap[2*(k+1)] ) + { + reorder = true; + break; + } + if( reorder ) + { + storage_type temp(size*2); + //assemble array that includes rank + for(int k = 0; k < size; ++k) + { + temp[2*k+0] = global_overlap[2*k]; + temp[2*k+1] = k; + } + //sort array + qsort(&temp[0],size,sizeof(INMOST_DATA_ENUM_TYPE)*2,comparator); + //create new group + MPI_Group oldg, newg; + MPI_Comm newcomm; + std::vector ranks(size); + for(int k = 0; k < size; ++k) + ranks[k] = temp[2*k+1]; + GUARD_MPI(MPI_Comm_group(comm,&oldg)); + GUARD_MPI(MPI_Group_incl(oldg,size,&ranks[0],&newg)); + GUARD_MPI(MPI_Comm_create(comm,newg,&newcomm)); + if( comm != INMOST_MPI_COMM_WORLD ) + { + GUARD_MPI(MPI_Comm_free(&comm)); + } + comm = newcomm; + //compute new rank + MPI_Comm_rank(comm,&rank); + //sort array pairs, so we don't need to exchange them again + qsort(&global_overlap[0],size,sizeof(INMOST_DATA_ENUM_TYPE)*2,comparator); + } + //now check that there are no overlaps of local indexes + //every mend must be equal to every mbeg + reorder = false; + for(int k = 0; k < size-1; k++) + if( global_overlap[2*k+1] != global_overlap[2*(k+1)] ) + { + //check that end is strictly greater then begin + if( global_overlap[2*k+1] < global_overlap[2*(k+1)] ) + { + if( initial_rank == 0 ) + { + std::cout << __FILE__ << ":" << __LINE__ << " Matrix index intervals are not complete:"; + std::cout << " processor " << k+0 << " interval " << global_overlap[2*(k+0)] << ":" << global_overlap[2*(k+0)+1]; + std::cout << " processor " << k+1 << " interval " << global_overlap[2*(k+1)] << ":" << global_overlap[2*(k+1)+1]; + std::cout << std::endl; + MPI_Abort(comm,-1000); + } + } + reorder = true; + } + if( reorder ) + { + storage_type old_overlap(global_overlap); + //move local bounds to get non-overlapping regions + for(int k = 0; k < size-1; k++) + while( global_overlap[2*k+1] > global_overlap[2*(k+1)] ) + { + //move bounds to equalize sizes + if( global_overlap[2*k+1] - global_overlap[2*k] < global_overlap[2*(k+1)+1] - global_overlap[2*(k+1)] ) + global_overlap[2*k+1]--; //move right bound of the current processor to left + else + global_overlap[2*(k+1)]++; //move left bound of the next processor to right + } + + //TODO: if we need to merge overlapping parts of the matrices - do it here + } + local_matrix_begin = global_overlap[2*rank+0]; + local_matrix_end = global_overlap[2*rank+1]; + for(int k = 0; k < size; k++) + global_to_proc[k+1] = global_overlap[2*k+1]; + } + MPI_Status stat; + INMOST_DATA_ENUM_TYPE ext_pos = local_matrix_end; + //may replace std::map here + small_hash global_to_local; + std::vector< std::pair > current_global_to_local; + std::vector< Sparse::Row::entry > send_row_data, recv_row_data; + std::vector< INMOST_DATA_ENUM_TYPE > send_row_sizes, recv_row_sizes; + std::vector incoming(4*size); + std::vector requests; + INMOST_DATA_ENUM_TYPE total_send = 0, total_recv = 0; + INMOST_DATA_ENUM_TYPE local_start = local_matrix_begin, local_end = local_matrix_end; + for(INMOST_DATA_ENUM_TYPE it = 0; it < overlap+1; it++) + { + total_send = 0, total_recv = 0; + current_global_to_local.clear(); + for(INMOST_DATA_ENUM_TYPE k = local_start; k < local_end; ++k) + { + Sparse::Row & r = m[k]; + INMOST_DATA_ENUM_TYPE jend = r.Size(), ind; + for(INMOST_DATA_ENUM_TYPE j = 0; j < jend; ++j) + { + ind = r.GetIndex(j); + if( ind < local_matrix_begin || ind >= local_matrix_end) + { + INMOST_DATA_ENUM_TYPE & recv_pos = global_to_local[ind]; + if( recv_pos == 0 ) //this number was not assigned yet + { + recv_pos = ext_pos++; + if( it < overlap ) current_global_to_local.push_back(std::make_pair(ind,recv_pos)); + } + } + } + } + if( it == overlap ) + current_global_to_local = global_to_local.serialize(); + std::sort(current_global_to_local.begin(),current_global_to_local.end()); + //if( !current_global_to_local.empty() ) + { + //check all the indexes that comes from other processors + //for every processor we need arrays: + // processor -> (array of index positions where to receive)) + // processor -> (array of index positions from where to send) + memset(&incoming[0],0,sizeof(INMOST_DATA_ENUM_TYPE)*size*2); + vector_exchange_recv.clear(); + vector_exchange_recv.push_back(0); + if( !current_global_to_local.empty() ) + { + INMOST_DATA_ENUM_TYPE proc_beg = GetProcessor(current_global_to_local.begin()->first), proc_end = GetProcessor(current_global_to_local.rbegin()->first)+1; + INMOST_DATA_ENUM_TYPE current_ind = 0; + for(INMOST_DATA_ENUM_TYPE proc = proc_beg; proc < proc_end; proc++) + { + bool first = true; + INMOST_DATA_ENUM_TYPE numind = static_cast(vector_exchange_recv.size() + 1); + while( current_ind < current_global_to_local.size() && current_global_to_local[current_ind].first < global_to_proc[proc+1] ) + { + INMOST_DATA_ENUM_TYPE k = current_global_to_local[current_ind].first; + if( first ) + { + vector_exchange_recv.push_back(proc); + vector_exchange_recv.push_back(1); + vector_exchange_recv.push_back(k); + first = false; + } + else + { + vector_exchange_recv[numind]++; + vector_exchange_recv.push_back(k); + } + current_ind++; + } + if( !first ) + { + incoming[proc]++; + incoming[proc+size] += vector_exchange_recv[numind]; + vector_exchange_recv[0]++; + } + } + } + + GUARD_MPI(MPI_Allreduce(&incoming[0],&incoming[2*size],size*2,INMOST_MPI_DATA_ENUM_TYPE,MPI_SUM,comm)); + //std::cout << GetRank() << " MPI_Allreduce " << __FILE__ << ":" << __LINE__ << " incoming " << incoming[size*2+rank] << " size " << incoming[size*3+rank] << std::endl; + //prepare array that helps exchanging vector values + requests.resize(2*vector_exchange_recv[0] + incoming[size*2+rank]); + INMOST_DATA_ENUM_TYPE j = 1; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //send rows that i want to receive + { + total_recv += vector_exchange_recv[j+1]; + GUARD_MPI(MPI_Isend(&vector_exchange_recv[j+1],1,INMOST_MPI_DATA_ENUM_TYPE,vector_exchange_recv[j],size+vector_exchange_recv[j],comm,&requests[k])); //send number of rows + GUARD_MPI(MPI_Isend(&vector_exchange_recv[j+2],vector_exchange_recv[j+1],INMOST_MPI_DATA_ENUM_TYPE,vector_exchange_recv[j],2*size+vector_exchange_recv[j],comm,&requests[k+vector_exchange_recv[0]])); //send row positions + j += vector_exchange_recv[j+1] + 2; + } + + recv_row_sizes.resize(incoming[size*3+rank]); + vector_exchange_send.resize(1+incoming[size*2+rank]*2+incoming[size*3+rank]); + vector_exchange_send[0] = 0; + j = 1; + for(INMOST_DATA_ENUM_TYPE k = 0; k < incoming[size*2+rank]; k++) //receive rows that others want from me + { + INMOST_DATA_ENUM_TYPE msgsize; + GUARD_MPI(MPI_Recv(&msgsize,1,INMOST_MPI_DATA_ENUM_TYPE,MPI_ANY_SOURCE,size+rank,comm,&stat)); //recv number of rows + vector_exchange_send[j++] = stat.MPI_SOURCE; + vector_exchange_send[j++] = msgsize; + //std::cout << GetRank() << " MPI_Irecv size " << msgsize << " rank " << stat.MPI_SOURCE << " tag " << 2*size+rank << __FILE__ << ":" << __LINE__ << std::endl; + GUARD_MPI(MPI_Irecv(&vector_exchange_send[j],msgsize,INMOST_MPI_DATA_ENUM_TYPE,stat.MPI_SOURCE,2*size+rank,comm,&requests[2*vector_exchange_recv[0]+k])); //recv rows + j += msgsize; + total_send += msgsize; + vector_exchange_send[0]++; + } + assert(total_send == incoming[size*3+rank]); + assert(vector_exchange_send[0] == incoming[size*2+rank]); + if( 2*vector_exchange_recv[0] + incoming[size*2+rank] > 0 ) + GUARD_MPI(MPI_Waitall(2*vector_exchange_recv[0] + incoming[size*2+rank],&requests[0],MPI_STATUSES_IGNORE)); + } + /* + else + { + vector_exchange_recv.resize(1,0); + vector_exchange_send.resize(1,0); + } + */ + if( it == overlap ) + { + //std::cout << rank << " reorder " << std::endl; + //now we need to reorder off-diagonal parts of the matrix + for(INMOST_DATA_ENUM_TYPE k = local_matrix_begin; k < local_end; ++k) + for(Sparse::Row::iterator jt = m[k].Begin(); jt != m[k].End(); ++jt) + if( global_to_local.is_present(jt->first) ) + jt->first = global_to_local[jt->first]; + else + { + assert(jt->first >= local_matrix_begin); + assert(jt->first < local_matrix_end); + } + local_vector_begin = local_matrix_begin; + local_vector_end = ext_pos; + { + // change indexes for recv array + INMOST_DATA_ENUM_TYPE i,j = 1,k; + //for(k = 0; k < GetRank(); k++) MPI_Barrier(comm); + //std::cout << "rank " << GetRank() << std::endl; + //std::cout << "recv:" << std::endl; + for(i = 0; i < vector_exchange_recv[0]; i++) + { + //std::cout << "proc " << vector_exchange_recv[j] << " size " << vector_exchange_recv[j+1] << std::endl; + j++; //skip processor number + for(k = 0; k < vector_exchange_recv[j]; ++k) + { + assert(global_to_local.is_present(vector_exchange_recv[j+k+1])); + vector_exchange_recv[j+k+1] = global_to_local[vector_exchange_recv[j+k+1]]; + assert(vector_exchange_recv[j+k+1] >= local_matrix_end); + } + j+=vector_exchange_recv[j]+1; //add vector length + size position + } + //check that indexes in send array are in local matrix bounds + //std::cout << "send:" << std::endl; +#ifndef NDEBUG + j = 1; + for(i = 0; i < vector_exchange_send[0]; i++) + { + //std::cout << "proc " << vector_exchange_send[j] << " size " << vector_exchange_send[j+1] << std::endl; + j++; //skip processor number + for(k = 0; k < vector_exchange_send[j]; ++k) + { + assert(vector_exchange_send[j+k+1] >= local_matrix_begin); + assert(vector_exchange_send[j+k+1] < local_matrix_end); + } + j+=vector_exchange_send[j]+1; //add vector length + size position + } +#endif + //for(k = GetRank(); k < GetSize(); k++) MPI_Barrier(comm); + } + //prepare array local->global + extended_indexes.resize(local_vector_end-local_matrix_end); + for(std::vector< std::pair >::iterator jt = current_global_to_local.begin(); jt != current_global_to_local.end(); ++jt) + extended_indexes[jt->second-local_matrix_end] = jt->first; + + send_storage.resize(total_send); + recv_storage.resize(total_recv); + send_requests.resize(vector_exchange_send[0]); + recv_requests.resize(vector_exchange_recv[0]); + + } + else + { + send_row_sizes.resize(total_send); + recv_row_sizes.resize(total_recv); + + INMOST_DATA_ENUM_TYPE j = 1, q = 0, f = 0, total_rows_send = 0, total_rows_recv = 0; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //recv sizes of rows + { + GUARD_MPI(MPI_Irecv(&recv_row_sizes[q],vector_exchange_recv[j+1],INMOST_MPI_DATA_ENUM_TYPE,vector_exchange_recv[j],3*size+vector_exchange_recv[j],comm,&requests[k])); + q += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1]+2; + } + j = 1; + q = 0; + + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_send[0]; k++) //send sizes of rows + { + for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_send[j+1]; r++) + { + send_row_sizes[q+r] = m[vector_exchange_send[j+2+r]].Size(); + total_rows_send += m[vector_exchange_send[j+2+r]].Size(); + } + GUARD_MPI(MPI_Isend(&send_row_sizes[q],vector_exchange_send[j+1],INMOST_MPI_DATA_ENUM_TYPE,vector_exchange_send[j],3*size+rank,comm,&requests[vector_exchange_recv[0]+k])); //recv rows + //remember processor numbers here + q += vector_exchange_send[j+1]; + j += vector_exchange_send[j+1]+2; + } + send_row_data.clear(); + send_row_data.reserve(total_rows_send); + + + j = 1; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_send[0]; k++) //accumulate data in array + { + for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_send[j+1]; r++) + send_row_data.insert(send_row_data.end(),m[vector_exchange_send[j+2+r]].Begin(),m[vector_exchange_send[j+2+r]].End()); + j += vector_exchange_send[j+1]+2; + } + + + //replace by mpi_waitsome + if( vector_exchange_recv[0]+vector_exchange_send[0] > 0 ) + GUARD_MPI(MPI_Waitall(vector_exchange_recv[0]+vector_exchange_send[0],&requests[0],MPI_STATUSES_IGNORE)); + + + j = 1; + q = 0; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //compute total size of data to receive + { + for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_recv[j+1]; r++) + total_rows_recv += recv_row_sizes[q+r]; + q += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1]+2; + } + recv_row_data.resize(total_rows_recv); + j = 1; + q = 0; + f = 0; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //receive row data + { + INMOST_DATA_ENUM_TYPE local_size = 0; + for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_recv[j+1]; r++) + local_size += recv_row_sizes[q+r]; + GUARD_MPI(MPI_Irecv(&recv_row_data[f],local_size,Sparse::GetRowEntryType(),vector_exchange_recv[j],4*size+vector_exchange_recv[j],comm,&requests[k])); + q += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1]+2; + f += local_size; + } + + + j = 1; + q = 0; + f = 0; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_send[0]; k++) //receive row data + { + INMOST_DATA_ENUM_TYPE local_size = 0; + for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_send[j+1]; r++) + local_size += send_row_sizes[q+r]; + GUARD_MPI(MPI_Isend(&send_row_data[f],local_size,Sparse::GetRowEntryType(),vector_exchange_send[j],4*size+rank,comm,&requests[k+vector_exchange_recv[0]])); + q += vector_exchange_send[j+1]; + j += vector_exchange_send[j+1]+2; + f += local_size; + } + + + local_start = local_end; + m.SetInterval(local_matrix_begin,ext_pos); + local_end = ext_pos; + if( vector_exchange_recv[0]+vector_exchange_send[0] > 0 ) + GUARD_MPI(MPI_Waitall(vector_exchange_recv[0]+vector_exchange_send[0],&requests[0],MPI_STATUSES_IGNORE)); + j = 1; + q = 0; + f = 0; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //extend matrix + { + for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_recv[j+1]; r++) + { + m[global_to_local[vector_exchange_recv[j+2+r]]] = Sparse::Row(&recv_row_data[f],&recv_row_data[f]+recv_row_sizes[q+r]); + f += recv_row_sizes[q+r]; + } + q += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1]+2; + } + } + //std::cout << it << "/" << overlap << " done" << std::endl; + } + two[0] = local_matrix_begin; + two[1] = local_end; + GUARD_MPI(MPI_Allgather(two,2,INMOST_MPI_DATA_ENUM_TYPE,&global_overlap[0],2,INMOST_MPI_DATA_ENUM_TYPE,comm)); + //std::cout << __FUNCTION__ << " done" << std::endl; +#endif + } + + void Solver::OrderInfo::RestoreMatrix(Sparse::Matrix & m) + { + //restore matrix size + m.SetInterval(initial_matrix_begin,initial_matrix_end); + //restore indexes + for(Sparse::Matrix::iterator it = m.Begin(); it != m.End(); ++it) + for(Sparse::Row::iterator jt = it->Begin(); jt != it->End(); ++jt) + if( jt->first >= initial_matrix_end ) + jt->first = extended_indexes[jt->first-initial_matrix_end]; + m.isParallel() = false; + have_matrix = false; +#if defined(USE_MPI) + if( comm != INMOST_MPI_COMM_WORLD ) + { + MPI_Comm_free(&comm); + comm = INMOST_MPI_COMM_WORLD; + } +#endif + //std::cout << __FUNCTION__ << std::endl; + } + + Solver::OrderInfo::~OrderInfo() + { +#if defined(USE_MPI) + if( comm != INMOST_MPI_COMM_WORLD ) + MPI_Comm_free(&comm); +#endif + } + + void Solver::OrderInfo::Clear() + { + global_to_proc.clear(); + global_overlap.clear(); + vector_exchange_recv.clear(); + vector_exchange_send.clear(); + send_storage.clear(); + recv_storage.clear(); + send_requests.clear(); + recv_requests.clear(); + extended_indexes.clear(); + local_vector_begin = local_vector_end = 0; + initial_matrix_begin = initial_matrix_end = 0; + local_matrix_begin = local_matrix_end = 0; + have_matrix = false; + } + + void Solver::OrderInfo::PrepareVector(Sparse::Vector & v) const + { + if( !have_matrix ) throw PrepareMatrixFirst; + v.SetInterval(local_vector_begin,local_vector_end); + v.isParallel() = true; + } + + void Solver::OrderInfo::RestoreVector(Sparse::Vector & v) const + { + assert(have_matrix); + if( v.isParallel() ) + { + v.SetInterval(initial_matrix_begin,initial_matrix_end); + v.isParallel() = false; + } + } + + Solver::OrderInfo::OrderInfo() : + global_to_proc(), + global_overlap(), + vector_exchange_recv(), + vector_exchange_send(), + send_storage(), + recv_storage(), + send_requests(), + recv_requests(), + extended_indexes() + { + comm = INMOST_MPI_COMM_WORLD; + rank = 0; + size = 1; + initial_matrix_begin = 0; + initial_matrix_end = 0; + local_matrix_begin = 0; + local_matrix_end = 0; + local_vector_begin = 0; + local_vector_end = 0; + have_matrix = false; + } + + Solver::OrderInfo::OrderInfo(const OrderInfo & other) + :global_to_proc(other.global_to_proc), global_overlap(other.global_overlap), + vector_exchange_recv(other.vector_exchange_recv), vector_exchange_send(other.vector_exchange_send), + extended_indexes(other.extended_indexes) + { +#if defined(USE_MPI) + if( other.comm == INMOST_MPI_COMM_WORLD ) + comm = INMOST_MPI_COMM_WORLD; + else MPI_Comm_dup(other.comm,&comm); +#else + comm = other.comm; +#endif + rank = other.rank; + size = other.size; + initial_matrix_begin = other.initial_matrix_begin; + initial_matrix_end = other.initial_matrix_end; + local_vector_begin = other.local_vector_begin; + local_vector_end = other.local_vector_end; + local_matrix_begin = other.local_matrix_begin; + local_matrix_end = other.local_matrix_end; + have_matrix = other.have_matrix; + send_storage.resize(other.send_storage.size()); + recv_storage.resize(other.recv_storage.size()); + send_requests.resize(other.send_requests.size()); + recv_requests.resize(other.recv_requests.size()); + } + + Solver::OrderInfo & Solver::OrderInfo::operator =(OrderInfo const & other) + { +#if defined(USE_MPI) + if( other.comm == INMOST_MPI_COMM_WORLD ) + comm = INMOST_MPI_COMM_WORLD; + else MPI_Comm_dup(other.comm,&comm); +#else + comm = other.comm; +#endif + global_to_proc = other.global_to_proc; + global_overlap = other.global_overlap; + vector_exchange_recv = other.vector_exchange_recv; + vector_exchange_send = other.vector_exchange_send; + extended_indexes = other.extended_indexes; + rank = other.rank; + size = other.size; + initial_matrix_begin = other.initial_matrix_begin; + initial_matrix_end = other.initial_matrix_end; + local_vector_begin = other.local_vector_begin; + local_vector_end = other.local_vector_end; + local_matrix_begin = other.local_matrix_begin; + local_matrix_end = other.local_matrix_end; + have_matrix = other.have_matrix; + send_storage.resize(other.send_storage.size()); + recv_storage.resize(other.recv_storage.size()); + send_requests.resize(other.send_requests.size()); + recv_requests.resize(other.recv_requests.size()); + return *this; + } + + + INMOST_DATA_ENUM_TYPE Solver::OrderInfo::GetProcessor(INMOST_DATA_ENUM_TYPE gind) const + { + assert(have_matrix); + storage_type::const_iterator find = std::lower_bound(global_to_proc.begin(),global_to_proc.end(),gind); + assert(find != global_to_proc.end()); + if( (*find) == gind && find+1 != global_to_proc.end()) return static_cast(find - global_to_proc.begin()); + else return static_cast(find - global_to_proc.begin())-1; + } + void Solver::OrderInfo::GetOverlapRegion(INMOST_DATA_ENUM_TYPE proc, INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const + { + assert(have_matrix); + mbeg = global_overlap[proc*2+0]; + mend = global_overlap[proc*2+1]; + } + void Solver::OrderInfo::GetLocalRegion(INMOST_DATA_ENUM_TYPE proc, INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const + { + assert(have_matrix); + mbeg = global_to_proc[proc+0]; + mend = global_to_proc[proc+1]; + } + + + void Solver::OrderInfo::Update(Sparse::Vector & x) + { + //std::cout << __FUNCTION__ << " start" << std::endl; +#if defined(USE_MPI) + if( GetSize() == 1 ) return; +#if defined(USE_OMP) +#pragma omp single +#endif + { + //use MPI_Put/MPI_Get to update vector + assert(x.isParallel()); //the vector was prepared + INMOST_DATA_ENUM_TYPE i, j = 1, k, l = 0; + int ierr; + for(i = 0; i < vector_exchange_recv[0]; i++) + { + //std::cout << GetRank() << " MPI_Irecv size " << vector_exchange_recv[j+1] << " dest " << vector_exchange_recv[j] << " tag " << vector_exchange_recv[j]*size+rank << std::endl; + GUARD_MPI(MPI_Irecv(&recv_storage[l],vector_exchange_recv[j+1],INMOST_MPI_DATA_REAL_TYPE,vector_exchange_recv[j],vector_exchange_recv[j]*size+rank,comm,&recv_requests[i])); + l += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1] + 2; + } + j = 1, l = 0; + for(i = 0; i < vector_exchange_send[0]; i++) + { + //std::cout << GetRank() << " MPI_Isend size " << vector_exchange_send[j+1] << " dest " << vector_exchange_send[j] << " tag " << rank*size+vector_exchange_send[j] << std::endl; + for(k = 0; k < vector_exchange_send[j+1]; k++) + send_storage[l+k] = x[vector_exchange_send[k+j+2]]; + GUARD_MPI(MPI_Isend(&send_storage[l],vector_exchange_send[j+1],INMOST_MPI_DATA_REAL_TYPE,vector_exchange_send[j],rank*size+vector_exchange_send[j],comm,&send_requests[i])); + l += vector_exchange_send[j+1]; + j += vector_exchange_send[j+1] + 2; + } + if( vector_exchange_recv[0] > 0 ) + { + GUARD_MPI(MPI_Waitall(static_cast(recv_requests.size()),&recv_requests[0],MPI_STATUSES_IGNORE)); + j = 1, l = 0; + for(i = 0; i < vector_exchange_recv[0]; i++) + { + for(k = 0; k < vector_exchange_recv[j+1]; k++) + x[vector_exchange_recv[k+j+2]] = recv_storage[l+k]; + l += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1] + 2; + } + } + if( vector_exchange_send[0] > 0 ) + { + GUARD_MPI(MPI_Waitall(static_cast(send_requests.size()),&send_requests[0],MPI_STATUSES_IGNORE)); + } + } +#else + (void) x; +#endif + //std::cout << __FUNCTION__ << " end" << std::endl; + } + void Solver::OrderInfo::Accumulate(Sparse::Vector & x) + { + //std::cout << __FUNCTION__ << " start" << std::endl; +#if defined(USE_MPI) + if( GetSize() == 1 ) return; +#if defined(USE_OMP) +#pragma omp single +#endif + { + //use MPI_Put/MPI_Get to update vector + assert(x.isParallel()); //the vector was prepared + INMOST_DATA_ENUM_TYPE i, j = 1, k, l = 0; + int ierr; + for(i = 0; i < vector_exchange_send[0]; i++) + { + //std::cout << GetRank() << " MPI_Irecv size " << vector_exchange_send[j+1] << " dest " << vector_exchange_send[j] << " tag " << vector_exchange_send[j]*size+rank << std::endl; + GUARD_MPI(MPI_Irecv(&send_storage[l],vector_exchange_send[j+1],INMOST_MPI_DATA_REAL_TYPE,vector_exchange_send[j],vector_exchange_send[j]*size+rank,comm,&send_requests[i])); + l += vector_exchange_send[j+1]; + j += vector_exchange_send[j+1] + 2; + } + j = 1, l = 0; + for(i = 0; i < vector_exchange_recv[0]; i++) + { + for(k = 0; k < vector_exchange_recv[j+1]; k++) + recv_storage[l+k] = x[vector_exchange_recv[k+j+2]]; + //std::cout << GetRank() << " MPI_Isend size " << vector_exchange_recv[j+1] << " dest " << vector_exchange_recv[j] << " tag " << rank*size+vector_exchange_recv[j] << std::endl; + GUARD_MPI(MPI_Isend(&recv_storage[l],vector_exchange_recv[j+1],INMOST_MPI_DATA_REAL_TYPE,vector_exchange_recv[j],rank*size+vector_exchange_recv[j],comm,&recv_requests[i])); + l += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1] + 2; + } + if( vector_exchange_send[0] > 0 ) + { + //std::cout << GetRank() << " Waitall send " << send_requests.size() << std::endl; + GUARD_MPI(MPI_Waitall(static_cast(send_requests.size()),&send_requests[0],MPI_STATUSES_IGNORE)); + j = 1, l = 0; + for(i = 0; i < vector_exchange_send[0]; i++) + { + for(k = 0; k < vector_exchange_send[j+1]; k++) + x[vector_exchange_send[k+j+2]] += send_storage[l+k]; + l += vector_exchange_send[j+1]; + j += vector_exchange_send[j+1] + 2; + } + } + if( vector_exchange_recv[0] > 0 ) + { + //std::cout << GetRank() << " Waitall recv " << recv_requests.size() << std::endl; + GUARD_MPI(MPI_Waitall(static_cast(recv_requests.size()),&recv_requests[0],MPI_STATUSES_IGNORE)); + } + } +#else + (void) x; +#endif + //std::cout << __FUNCTION__ << " end" << std::endl; + } + /* + void Solver::OrderInfo::ScalarProd(Vector const & left, Vector const & right, INMOST_DATA_ENUM_TYPE index_begin, INMOST_DATA_ENUM_TYPE index_end, INMOST_DATA_REAL_TYPE & sum) const + { + INMOST_DATA_INTEGER_TYPE ibeg = index_begin, iend = index_end; +#if defined(USE_OMP) +#pragma omp for reduction(+:sum) +#endif + for(INMOST_DATA_INTEGER_TYPE i = ibeg; i < iend; ++i) + { + sum += left[i]*right[i]; + } + Integrate(&sum,1); + } + */ + + + + + + + + + + //====================================================================== + //SOLVER SOURCE CODE + //====================================================================== + void Solver::Initialize(int * argc, char *** argv, const char * database) + { + (void)database; + (void)argc; + (void)argv; + if( database != NULL ) + { + FILE * f = fopen(database,"r"); + if( f ) + { + //std::fstream file(database,std::ios::in); + char str[4096]; + //while( !file.eof() && file.getline(str,4096) ) + while( !feof(f) && fgets(str,4096,f) ) + { + int k = 0, l; + for(k = 0; k < (int)strlen(str); ++k) + { + if( str[k] == ':' ) break; + } + if( k == strlen(str) ) continue; //invalid line + for(l = 0; l < k; ++l) str[l] = tolower(str[l]); + l = (int)strlen(str)-1; // Right-trim string + while(l > 0 && isspace(str[l]) ) --l; + str[l+1] = 0; + l = k+1; + while(l < (int)strlen(str) && isspace(str[l]) ) ++l; + if( l == strlen(str) ) continue; //skip empty entry + if( !strncmp(str,"petsc",k) ) + petsc_database_file = std::string(str+l); + else if( !strncmp(str,"trilinos_ifpack",k) ) + trilinos_ifpack_database_file = std::string(str+l); + else if( !strncmp(str,"trilinos_aztec",k) ) + trilinos_aztec_database_file = std::string(str+l); + else if( !strncmp(str,"trilinos_ml",k) ) + trilinos_ml_database_file = std::string(str+l); + else if( !strncmp(str,"trilinos_belos",k) ) + trilinos_belos_database_file = std::string(str+l); + else if( !strncmp(str,"ani",k) ) + ani_database_file = std::string(str+l); + else if( !strncmp(str,"fcbiilu2",k) ) + fcbiilu2_database_file = std::string(str+l); + else if( !strncmp(str,"k3biilu2",k) ) + k3biilu2_database_file = std::string(str+l); + else if( !strncmp(str,"superlu",k) ) + superlu_database_file = std::string(str+l); + } + //file.close(); + fclose(f); + } + } + //std::cout << "PETSc \"" << petsc_database_file << "\"" << std::endl; + //std::cout << "Trilinos_Ifpack \"" << trilinos_ifpack_database_file << "\"" << std::endl; +#if defined(USE_SOLVER_PETSC) + SolverInitializePetsc(argc,argv,petsc_database_file.c_str()); +#endif +#if defined(USE_SOLVER_SUPERLU) + SolverInitializeSuperLU(argc,argv,superlu_database_file.c_str()); +#endif +#if defined(USE_SOLVER_ANI) + SolverInitializeAni(argc,argv,ani_database_file.c_str()); +#endif +#if defined(HAVE_SOLVER_FCBIILU2) + SolverInitializeFcbiilu2(argc,argv,fcbiilu2_database_file.c_str()); +#endif +#if defined(HAVE_SOLVER_K3BIILU2) + SolverInitializeK3biilu2(argc,argv,k3biilu2_database_file.c_str()); +#endif +#if defined(USE_MPI) + { + int flag = 0; + int ierr = 0; + MPI_Initialized(&flag); + if( !flag ) + { + ierr = MPI_Init(argc,argv); + if( ierr != MPI_SUCCESS ) + { + std::cout << __FILE__ << ":" << __LINE__ << "problem in MPI_Init" << std::endl; + } + } + } +#endif +#if defined(USE_SOLVER_SUPERLU) + +#endif + Sparse::CreateRowEntryType(); + is_initialized = true; + } + + void Solver::Finalize() + { + Sparse::DestroyRowEntryType(); +#if defined(USE_SOLVER_PETSC) + SolverFinalizePetsc(); +#endif +#if defined(USE_SOLVER_ANI) + SolverFinalizeAni(); +#endif +#if defined(HAVE_SOLVER_FCBIILU2) + SolverFinalizeFcbiilu2(); +#endif +#if defined(HAVE_SOLVER_K3BIILU2) + SolverFinalizeK3biilu2(); +#endif +#if defined(USE_MPI) + { + int flag = 0; + MPI_Finalized(&flag); + if( !flag ) + MPI_Finalize(); + } +#endif + is_initialized = false; + is_finalized = true; + } + void Solver::SetParameterEnum(std::string name, INMOST_DATA_ENUM_TYPE val) + { + if( name == "maximum_iterations" ) + maximum_iterations = val; + else if( name == "rescale_iterations" ) + preconditioner_rescale_iterations = val; + else if( name == "condition_estimation" ) + preconditioner_condition_estimation = val; + else if( name == "adapt_ddpq_tolerance" ) + preconditioner_adapt_ddpq_tolerance = val; + else if( name == "schwartz_overlap" ) + additive_schwartz_overlap = val; + else if( name == "gmres_substeps" ) + solver_gmres_substeps = val; + else if( name == "reorder_nonzeros" ) + preconditioner_reorder_nonzero = val; + /* Block below leads to confusion - parameters would be reset by preset values during setup + else if( _pack == INNER_ILU2 || _pack == INNER_MLILUC ) + { + try + { + //This leads to confusion - + IterativeMethod * method = (IterativeMethod *)solver_data; + if (name[0] == ':') + method->EnumParameter(name.substr(1, name.size() - 1)) = val; + else if (name == "overlap") additive_schwartz_overlap = val; + else method->EnumParameter(name) = val; + } + catch(...) + { + std::cout << "Parameter " << name << " of intergral type is unknown" << std::endl; + } + } + */ + else std::cout << "Parameter " << name << " of integral type is unknown" << std::endl; + } + void Solver::SetParameterReal(std::string name, INMOST_DATA_REAL_TYPE val) + { + if( name == "absolute_tolerance" ) + absolute_tolerance = val; + else if( name == "relative_tolerance" ) + relative_tolerance = val; + else if( name == "divergence_tolerance" ) + divergence_tolerance = val; + else if( name == "drop_tolerance" ) + preconditioner_drop_tolerance = val; + else if( name == "reuse_tolerance" ) + preconditioner_reuse_tolerance = val; + else if( name == "ddpq_tolerance" ) + preconditioner_ddpq_tolerance = val; + else if( name == "fill_level" ) + preconditioner_fill_level = val; + /* Block below leads to confusion - parameters would be reset by preset values during setup + else if( _pack == INNER_ILU2 || _pack == INNER_MLILUC ) + { + try + { + IterativeMethod * method = (IterativeMethod *)solver_data; + if (name[0] == ':') method->RealParameter(name.substr(1, name.size() - 1)) = val; + else method->RealParameter(name) = val; + } + catch(...) + { + std::cout << "Parameter " << name << " of real type is unknown" << std::endl; + } + } + */ + else std::cout << "Parameter " << name << " of real type is unknown" << std::endl; + } + Solver::Solver(Type pack, std::string _name, INMOST_MPI_Comm _comm) + { + additive_schwartz_overlap = DEFAULT_ADDITIVE_SCHWARTZ_OVERLAP; + maximum_iterations = DEFAULT_MAXIMUM_ITERATIONS; + absolute_tolerance = DEFAULT_ABSOLUTE_TOLERANCE; + relative_tolerance = DEFAULT_RELATIVE_TOLERANCE; + divergence_tolerance = DEFAULT_DIVERGENCE_TOLERANCE; + preconditioner_ddpq_tolerance = DEFAULT_PRECONDITIONER_DDPQ_TOLERANCE; + preconditioner_drop_tolerance = DEFAULT_PRECONDITIONER_DROP_TOLERANCE; + preconditioner_reuse_tolerance = DEFAULT_PRECONDITIONER_REUSE_TOLERANCE; + preconditioner_reorder_nonzero = DEFAULT_PRECONDITIONER_REORDER_NONZEROS; + preconditioner_rescale_iterations = DEFAULT_PRECONDITIONER_RESCALE_ITERS; + preconditioner_fill_level = DEFAULT_PRECONDITIONER_FILL_LEVEL; + preconditioner_adapt_ddpq_tolerance = DEFAULT_PRECONDITIONER_ADAPT_DDPQ_TOLERANCE; + preconditioner_condition_estimation = DEFAULT_PRECONDITIONER_CONDITION_ESTIMATION; + solver_gmres_substeps = DEFAULT_SOLVER_GMRES_SUBSTEPS; + comm = _comm; + _pack = pack; + name = _name; + solver_data = NULL; + local_size = global_size = 0; + last_it = 0; + last_resid = 0; + matrix_data = rhs_data = solution_data = precond_data = NULL; +#if defined(USE_SOLVER_PETSC) + if( _pack == PETSc ) + { + SolverInitDataPetsc(&solver_data,_comm,name.c_str()); + } +#endif +#if defined(USE_SOLVER_ANI) + if( _pack == ANI ) + { + SolverInitDataAni(&solver_data,_comm,name.c_str()); + } +#endif +#if defined(HAVE_SOLVER_FCBIILU2) + if( _pack == FCBIILU2 ) + { + SolverInitDataFcbiilu2(&solver_data,_comm,name.c_str()); + } +#endif +#if defined(HAVE_SOLVER_K3BIILU2) + if( _pack == K3BIILU2 ) + { + SolverInitDataK3biilu2(&solver_data,_comm,name.c_str()); + } +#endif +#if defined(USE_SOLVER_SUPERLU) + if( _pack == SUPERLU ) + { + SolverInitDataSuperLU(&solver_data); + } +#endif +#if defined(USE_SOLVER_TRILINOS) + if( _pack == Trilinos_Aztec || + _pack == Trilinos_Belos || + _pack == Trilinos_ML || + _pack == Trilinos_Ifpack) + { + std::pair * problem = + new std::pair; + problem->first = _name; + solver_data = static_cast(problem); + } +#endif + if( _pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILUC || _pack == INNER_MPTILU2) + { + Method * prec; + if (_pack == INNER_ILU2) + { +#if defined(__SOLVER_ILU2__) + prec = new ILU2_preconditioner(info); +#else + std::cout << "Sorry, ILU2 preconditioner is not included in this release" << std::endl; + prec = NULL; +#endif + } + else if( _pack == INNER_DDPQILUC ) + { +#if defined(__SOLVER_DDPQILUC2__) + prec = new ILUC_preconditioner(info); +#else + std::cout << "Sorry, multilevel condition estimation crout-ilu preconditioner with reordering for diagonal dominance is not included in this release" << std::endl; + prec = NULL; +#endif + } + else if( _pack == INNER_MPTILUC ) + { +#if defined(__SOLVER_MTILUC2__) + prec = new MTILUC_preconditioner(info); +#else + std::cout << "Sorry, maximum product transverse condition estimation crout-ilu preconditioner is not included in this release" << std::endl; + prec = NULL; +#endif + } + else if( _pack == INNER_MPTILU2 ) + { +#if defined(__SOLVER_MTILU2__) + prec = new MTILU2_preconditioner(info); +#else + std::cout << "Sorry, maximum product transverse ilu2 preconditioner is not included in this release" << std::endl; + prec = NULL; +#endif + } + else prec = NULL; + solver_data = new KSOLVER(prec, info); + } + } + Solver::Solver(const Solver & other) + { + comm = other.comm; +#if defined(USE_SOLVER_PETSC) + if( _pack == PETSc ) + { + SolverCopyDataPetsc(&solver_data,other.solver_data,comm); + if( other.matrix_data != NULL ) + { + MatrixCopyDataPetsc(&matrix_data,other.matrix_data); + SolverSetMatrixPetsc(solver_data,matrix_data,false,false); + } + if( other.rhs_data != NULL ) + VectorCopyDataPetsc(&rhs_data,other.rhs_data); + if( other.solution_data != NULL ) + VectorCopyDataPetsc(&solution_data,other.solution_data); + } +#endif +#if defined(USE_SOLVER_ANI) + if( _pack == ANI ) + { + SolverCopyDataAni(&solver_data,other.solver_data,comm); + if( other.matrix_data != NULL ) + { + MatrixCopyDataAni(&matrix_data,other.matrix_data); + SolverSetMatrixAni(solver_data,matrix_data,false,false); + } + if( other.rhs_data != NULL ) + VectorCopyDataAni(&rhs_data,other.rhs_data); + if( other.solution_data != NULL ) + VectorCopyDataAni(&solution_data,other.solution_data); + } +#endif +#if defined(HAVE_SOLVER_FCBIILU2) + if( _pack == FCBIILU2 ) + { + SolverCopyDataFcbiilu2(&solver_data,other.solver_data,comm); + if( other.matrix_data != NULL ) + { + MatrixCopyDataFcbiilu2(&matrix_data,other.matrix_data); + SolverSetMatrixFcbiilu2(solver_data,matrix_data,false,false); + } + if( other.rhs_data != NULL ) + VectorCopyDataFcbiilu2(&rhs_data,other.rhs_data); + if( other.solution_data != NULL ) + VectorCopyDataFcbiilu2(&solution_data,other.solution_data); + } +#endif +#if defined(HAVE_SOLVER_K3BIILU2) + if( _pack == K3BIILU2 ) + { + SolverCopyDataK3biilu2(&solver_data,other.solver_data,comm); + if( other.matrix_data != NULL ) + { + MatrixCopyDataK3biilu2(&matrix_data,other.matrix_data); + SolverSetMatrixK3biilu2(solver_data,matrix_data,false,false); + } + if( other.rhs_data != NULL ) + VectorCopyDataK3biilu2(&rhs_data,other.rhs_data); + if( other.solution_data != NULL ) + VectorCopyDataK3biilu2(&solution_data,other.solution_data); + } +#endif +#if defined(USE_SOLVER_TRILINOS) + if( _pack == Trilinos_Aztec || + _pack == Trilinos_Belos || + _pack == Trilinos_ML || + _pack == Trilinos_Ifpack) + { + throw - 1; //You should not really want to copy solver's information + } +#endif + if (_pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILUC || _pack == INNER_MPTILU2) + { + throw - 1; //You should not really want to copy solver's information + } + } + void Solver::Clear() + { + local_size = global_size = 0; + info.Clear(); +#if defined(USE_SOLVER_PETSC) + if( _pack == PETSc ) + { + if( matrix_data != NULL ) + MatrixDestroyDataPetsc(&matrix_data); + if( rhs_data != NULL ) + VectorDestroyDataPetsc(&rhs_data); + if( solution_data != NULL ) + VectorDestroyDataPetsc(&solution_data); + SolverDestroyDataPetsc(&solver_data); + } +#endif +#if defined(USE_SOLVER_ANI) + if( _pack == ANI ) + { + if( matrix_data != NULL ) + MatrixDestroyDataAni(&matrix_data); + if( rhs_data != NULL ) + VectorDestroyDataAni(&rhs_data); + if( solution_data != NULL ) + VectorDestroyDataAni(&solution_data); + SolverDestroyDataAni(&solver_data); + } +#endif +#if defined(HAVE_SOLVER_FCBIILU2) + if( _pack == FCBIILU2 ) + { + if( matrix_data != NULL ) + MatrixDestroyDataFcbiilu2(&matrix_data); + if( rhs_data != NULL ) + VectorDestroyDataFcbiilu2(&rhs_data); + if( solution_data != NULL ) + VectorDestroyDataFcbiilu2(&solution_data); + SolverDestroyDataFcbiilu2(&solver_data); + } +#endif +#if defined(HAVE_SOLVER_K3BIILU2) + if( _pack == K3BIILU2 ) + { + if( matrix_data != NULL ) + MatrixDestroyDataK3biilu2(&matrix_data); + if( rhs_data != NULL ) + VectorDestroyDataK3biilu2(&rhs_data); + if( solution_data != NULL ) + VectorDestroyDataK3biilu2(&solution_data); + SolverDestroyDataK3biilu2(&solver_data); + } +#endif +#if defined(USE_SOLVER_TRILINOS) + if( _pack == Trilinos_Aztec || + _pack == Trilinos_Belos || + _pack == Trilinos_ML || + _pack == Trilinos_Ifpack) + { + if( matrix_data != NULL ) + { + delete static_cast(matrix_data); + matrix_data = NULL; + } + if( solver_data != NULL ) + { + delete static_cast *>(solver_data); + solver_data = NULL; + } + } +#endif +#if defined(USE_SOLVER_SUPERLU) + if(_pack == SUPERLU ) + { + SolverDestroyDataSuperLU(&solver_data); + matrix_data = NULL; + } +#endif + if (_pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILUC || _pack == INNER_MPTILU2) + { + if( matrix_data != NULL ) + { + delete (Sparse::Matrix * )matrix_data; + matrix_data = NULL; + } + if( solver_data != NULL ) + { + delete (Method *)solver_data; + solver_data = NULL; + } + } + } + Solver::~Solver() + { + Clear(); + } + Solver & Solver::operator =(Solver const & other) + { + if( this != &other ) + { + comm = other.comm; +#if defined(USE_SOLVER_PETSC) + if( _pack == PETSc ) + { + SolverAssignDataPetsc(solver_data,other.solver_data); + if( other.matrix_data != NULL ) + { + if( matrix_data != NULL ) + MatrixAssignDataPetsc(matrix_data,other.matrix_data); + else + MatrixCopyDataPetsc(&matrix_data,other.matrix_data); + SolverSetMatrixPetsc(solver_data,matrix_data,false,false); + } + if( other.rhs_data != NULL ) + { + if( rhs_data != NULL ) + VectorAssignDataPetsc(rhs_data,other.rhs_data); + else + VectorCopyDataPetsc(&rhs_data,other.rhs_data); + } + if( other.solution_data != NULL ) + { + if( solution_data != NULL ) + VectorAssignDataPetsc(solution_data,other.solution_data); + else + VectorCopyDataPetsc(&solution_data,other.solution_data); + } + } +#endif +#if defined(USE_SOLVER_ANI) + if( _pack == ANI ) + { + SolverAssignDataAni(solver_data,other.solver_data); + if( other.matrix_data != NULL ) + { + if( matrix_data != NULL ) + MatrixAssignDataAni(matrix_data,other.matrix_data); + else + MatrixCopyDataAni(&matrix_data,other.matrix_data); + SolverSetMatrixAni(solver_data,matrix_data,false,false); + } + if( other.rhs_data != NULL ) + { + if( rhs_data != NULL ) + VectorAssignDataAni(rhs_data,other.rhs_data); + else + VectorCopyDataAni(&rhs_data,other.rhs_data); + } + if( other.solution_data != NULL ) + { + if( solution_data != NULL ) + VectorAssignDataAni(solution_data,other.solution_data); + else + VectorCopyDataAni(&solution_data,other.solution_data); + } + } +#endif +#if defined(HAVE_SOLVER_FCBIILU2) + if( _pack == FCBIILU2 ) + { + SolverAssignDataFcbiilu2(solver_data,other.solver_data); + if( other.matrix_data != NULL ) + { + if( matrix_data != NULL ) + MatrixAssignDataFcbiilu2(matrix_data,other.matrix_data); + else + MatrixCopyDataFcbiilu2(&matrix_data,other.matrix_data); + SolverSetMatrixFcbiilu2(solver_data,matrix_data,false,false); + } + if( other.rhs_data != NULL ) + { + if( rhs_data != NULL ) + VectorAssignDataFcbiilu2(rhs_data,other.rhs_data); + else + VectorCopyDataFcbiilu2(&rhs_data,other.rhs_data); + } + if( other.solution_data != NULL ) + { + if( solution_data != NULL ) + VectorAssignDataFcbiilu2(solution_data,other.solution_data); + else + VectorCopyDataFcbiilu2(&solution_data,other.solution_data); + } + } +#endif +#if defined(HAVE_SOLVER_K3BIILU2) + if( _pack == K3BIILU2 ) + { + SolverAssignDataK3biilu2(solver_data,other.solver_data); + if( other.matrix_data != NULL ) + { + if( matrix_data != NULL ) + MatrixAssignDataK3biilu2(matrix_data,other.matrix_data); + else + MatrixCopyDataK3biilu2(&matrix_data,other.matrix_data); + SolverSetMatrixK3biilu2(solver_data,matrix_data,false,false); + } + if( other.rhs_data != NULL ) + { + if( rhs_data != NULL ) + VectorAssignDataK3biilu2(rhs_data,other.rhs_data); + else + VectorCopyDataK3biilu2(&rhs_data,other.rhs_data); + } + if( other.solution_data != NULL ) + { + if( solution_data != NULL ) + VectorAssignDataK3biilu2(solution_data,other.solution_data); + else + VectorCopyDataK3biilu2(&solution_data,other.solution_data); + } + } +#endif +#if defined(USE_SOLVER_TRILINOS) + if( _pack == Trilinos_Aztec || + _pack == Trilinos_Belos || + _pack == Trilinos_ML || + _pack == Trilinos_Ifpack) + { + throw - 1; //You should not really want to copy solver's information + } +#endif + if (_pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILUC || _pack == INNER_MPTILU2) + { + throw - 1; //You should not really want to copy solver's information + } + } + return *this; + } + + void Solver::SetMatrix(Sparse::Matrix & A, bool ModifiedPattern, bool OldPreconditioner) + { + (void) OldPreconditioner; + bool ok = false; +#if defined(USE_SOLVER_PETSC) + if( _pack == PETSc ) + { + bool modified_pattern = ModifiedPattern; + //~ if( A.comm != comm ) throw DifferentCommunicatorInSolver; + if( matrix_data == NULL ) + { + MatrixInitDataPetsc(&matrix_data,A.GetCommunicator(),A.GetName().c_str()); + modified_pattern = true; + //printf("matrix %p\n",matrix_data); + } + INMOST_DATA_ENUM_TYPE mbeg,mend; + A.GetInterval(mbeg,mend); + if( modified_pattern ) + { + local_size = A.Size(); +#if defined(USE_MPI) + MPI_Allreduce(&local_size,&global_size,1,INMOST_MPI_DATA_ENUM_TYPE,MPI_SUM,comm); +#else + global_size = local_size; +#endif + int max = 0; + { + int * diag_nonzeroes = new int[local_size]; + int * off_diag_nonzeroes = new int[local_size]; + unsigned k = 0; + + for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); ++it) + { + diag_nonzeroes[k] = off_diag_nonzeroes[k] = 0; + for(INMOST_DATA_ENUM_TYPE i = 0; i < it->Size(); i++) + { + INMOST_DATA_ENUM_TYPE index = it->GetIndex(i); + if( index < mbeg || index > mend-1 ) off_diag_nonzeroes[k]++; + else diag_nonzeroes[k]++; + } + if( diag_nonzeroes[k] + off_diag_nonzeroes[k] > max ) max = diag_nonzeroes[k] + off_diag_nonzeroes[k]; + k++; + } + MatrixPreallocatePetsc(matrix_data,local_size,global_size,diag_nonzeroes,off_diag_nonzeroes); + delete [] diag_nonzeroes; + delete [] off_diag_nonzeroes; + } + if( max > 0 ) + { + int * col_positions = new int[max]; + double * col_values = new double[max]; + unsigned k = 0, m; + for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); ++it) + { + m = 0; + for(INMOST_DATA_ENUM_TYPE i = 0; i < it->Size(); i++) + { + col_positions[m] = it->GetIndex(i); + col_values[m] = it->GetValue(i); + m++; + } + MatrixFillPetsc(matrix_data,mbeg+k,m,col_positions,col_values); + k++; + } + delete [] col_positions; + delete [] col_values; + } + } + else + { + unsigned max = 0; + for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); ++it) + if( it->Size() > max ) max = it->Size(); + int * col_positions = new int[max]; + double * col_values = new double[max]; + unsigned k = 0, m; + for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); ++it) + { + m = 0; + for(INMOST_DATA_ENUM_TYPE i = 0; i < it->Size(); i++) + { + col_positions[m] = it->GetIndex(i); + col_values[m] = it->GetValue(i); + m++; + } + MatrixFillPetsc(matrix_data,mbeg+k,m,col_positions,col_values); + k++; + } + delete [] col_positions; + delete [] col_values; + } + MatrixFinalizePetsc(matrix_data); + if( petsc_database_file == "" ) //set parameters if no file is set + { + SolverSetDropTolerancePetsc(solver_data,preconditioner_drop_tolerance); + SolverSetFillLevelPetsc(solver_data,preconditioner_fill_level); + SolverSetOverlapPetsc(solver_data,additive_schwartz_overlap); + } + SolverSetMatrixPetsc(solver_data,matrix_data,modified_pattern,OldPreconditioner); + ok = true; + } +#endif +#if defined(USE_SOLVER_ANI) + if( _pack == ANI ) + { + bool modified_pattern = ModifiedPattern; + if( matrix_data == NULL ) + { + MatrixInitDataAni(&matrix_data,A.GetCommunicator(),A.GetName().c_str()); + modified_pattern = true; + } + if( modified_pattern ) + { + global_size = local_size = A.Size(); + + MatrixDestroyDataAni(&matrix_data); + MatrixInitDataAni(&matrix_data,A.GetCommunicator(),A.GetName().c_str()); + INMOST_DATA_ENUM_TYPE nnz = 0, k = 0, q = 1, shift = 1; + int n = A.Size(); + int * ia = (int *)malloc(sizeof(int)*(n+1)); + for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) nnz += it->Size(); + int * ja = (int *)malloc(sizeof(int)*nnz); + double * values = (double *) malloc(sizeof(double)*nnz); + ia[0] = shift; + for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) + { + for(Sparse::Row::iterator jt = it->Begin(); jt != it->End(); jt++) + { + ja[k] = jt->first + 1; + values[k] = jt->second; + k++; + } + shift += it->Size(); + ia[q++] = shift; + } + MatrixFillAni(matrix_data,n,ia,ja,values); + } + else + { + INMOST_DATA_ENUM_TYPE nnz = 0, k = 0; + for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) nnz += it->Size(); + double * values = (double *)malloc(sizeof(double)*nnz); + k = 0; + for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) + for(Sparse::Row::iterator jt = it->Begin(); jt != it->End(); jt++) + values[k++] = jt->second; + MatrixFillValuesAni(matrix_data,values); + } + MatrixFinalizeAni(matrix_data); + SolverSetMatrixAni(solver_data,matrix_data,modified_pattern,OldPreconditioner); + ok = true; + } +#endif +#if defined(HAVE_SOLVER_FCBIILU2) + if( _pack == FCBIILU2 ) + { + bool modified_pattern = ModifiedPattern; + //~ if( A.comm != comm ) throw DifferentCommunicatorInSolver; + if( matrix_data == NULL ) + { + MatrixInitDataFcbiilu2(&matrix_data,A.GetCommunicator(),A.GetName().c_str()); + modified_pattern = true; + } + if( modified_pattern ) + { + global_size = local_size = A.Size(); + + MatrixDestroyDataFcbiilu2(&matrix_data); + MatrixInitDataFcbiilu2(&matrix_data,A.GetCommunicator(),A.GetName().c_str()); + INMOST_DATA_ENUM_TYPE nnz = 0, k = 0, q = 1, shift = 1; + int nproc, myid; +#if defined(USE_MPI) + MPI_Comm_size(A.GetCommunicator(),&nproc); + MPI_Comm_rank(A.GetCommunicator(),&myid); +#else + nproc = 1; + myid = 0; +#endif + int * ibl = (int *)malloc(sizeof(int)*(nproc+1)); + ibl[0] = 0; + int n = A.Size(); +#if defined(USE_MPI) + INMOST_DATA_ENUM_TYPE mbeg,mend; + A.GetInterval(mbeg,mend); + n = mend - mbeg; + int block_end = mend; + MPI_Allgather(&block_end,1,MPI_INT,&ibl[1],1,MPI_INT,A.GetCommunicator()); +#else + ibl[1] = n; +#endif + int * ia = (int *)malloc(sizeof(int)*(n+1)); + for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) nnz += it->Size(); + int * ja = (int *)malloc(sizeof(int)*nnz); + double * values = (double *) malloc(sizeof(double)*nnz); + ia[0] = shift; + for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) + { + for(Sparse::Row::iterator jt = it->Begin(); jt != it->End(); jt++) + { + ja[k] = jt->first + 1; + values[k] = jt->second; + //std::cout<<"# q="<(matrix_data); + matrix_data = NULL; + } + local_size = A.Size(); +#if defined(USE_MPI) + MPI_Allreduce(&local_size,&global_size,1,INMOST_MPI_DATA_ENUM_TYPE,MPI_SUM,comm); +#else + global_size = local_size; +#endif + //std::cout << Comm.MyPID() << " " << "local size " << local_size << " global size " << global_size << std::endl; + int k; + int imbeg = static_cast(mbeg); + int imend = static_cast(mend); + int * temporary = new int[imend-imbeg]; + for(k = imbeg; k < imend; ++k) temporary[k-imbeg] = k; + //std::cout << Comm.MyPID() << " " << "Creating Epetra_Map" << std::endl; + Epetra_Map Map(static_cast(global_size),static_cast(local_size),temporary,0,Comm); + k = 0; + for(k = imbeg; k < imend; ++k) temporary[k-imbeg] = A[k].Size(); + //std::cout << Comm.MyPID() << " " << "Creating Epetra_CrsMatrix" << std::endl; + Epetra_CrsMatrix * Matrix = new Epetra_CrsMatrix(Copy,Map,temporary,true); + matrix_data = static_cast(Matrix); + delete [] temporary; + refill = false; + } + { + assert(matrix_data); + Epetra_CrsMatrix * Matrix = static_cast(matrix_data); + unsigned max = 0; + for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); ++it) + if( it->Size() > max ) max = it->Size(); + int * col_positions = new int[max]; + double * col_values = new double[max]; + for(INMOST_DATA_ENUM_TYPE k = mbeg; k < mend; ++k) + { + INMOST_DATA_ENUM_TYPE m = 0; + for(INMOST_DATA_ENUM_TYPE i = 0; i < A[k].Size(); i++) + { + col_positions[m] = A[k].GetIndex(i); + col_values[m] = A[k].GetValue(i); + m++; + } + int ret; + if( refill ) + ret = Matrix->ReplaceGlobalValues(k,m,col_values,col_positions); + else + ret = Matrix->InsertGlobalValues(k,m,col_values,col_positions); + if( ret != 0 ) + std::cout << "Problem reported by Trilinos! return code " << ret << std::endl; + } + delete [] col_positions; + delete [] col_values; + Matrix->FillComplete(); + //std::stringstream str; + //str << "epetra" << Comm.MyPID() << ".mat"; + //std::fstream file(str.str(),std::ios::out); + //file << *Matrix; + //file.close(); + assert(solver_data); + Epetra_LinearProblem * problem = &static_cast *>(solver_data)->second; + problem->SetOperator(Matrix); + } + ok = true; + } +#endif + if (_pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILUC || _pack == INNER_MPTILU2) + { + + Sparse::Matrix * mat = new Sparse::Matrix(A); + info.PrepareMatrix(*mat, additive_schwartz_overlap); + IterativeMethod * sol = (IterativeMethod *)solver_data; + sol->ReplaceMAT(*mat); + if( matrix_data != NULL ) delete (Sparse::Matrix *)matrix_data; + matrix_data = (void *)mat; + + sol->RealParameter(":tau") = preconditioner_drop_tolerance; + sol->RealParameter(":tau2") = preconditioner_reuse_tolerance; + sol->EnumParameter(":scale_iters") = preconditioner_rescale_iterations; + + if( _pack == INNER_DDPQILUC ) + { + sol->RealParameter(":ddpq_tau") = preconditioner_ddpq_tolerance; + sol->EnumParameter(":reorder_nnz") = preconditioner_reorder_nonzero; + sol->EnumParameter(":estimator") = preconditioner_condition_estimation; + sol->EnumParameter(":ddpq_tau_adapt") = preconditioner_adapt_ddpq_tolerance; + } + else if( _pack == INNER_MPTILUC ) + { + sol->EnumParameter(":estimator") = preconditioner_condition_estimation; + } + else if( _pack == INNER_ILU2 ) sol->EnumParameter(":fill") = static_cast(preconditioner_fill_level); + + if( sizeof(KSOLVER) == sizeof(BCGSL_solver) ) + sol->EnumParameter("levels") = solver_gmres_substeps; + + if (!sol->isInitialized()) + { + sol->Initialize(); + } + ok = true; + + } + if(!ok) throw NotImplemented; + } + +#if defined(ACCELERATED_CONDEST) + INMOST_DATA_REAL_TYPE Solver::Condest(INMOST_DATA_REAL_TYPE tol, INMOST_DATA_ENUM_TYPE maxiter) + { + if( matrix_data == NULL ) throw MatrixNotSetInSolver; + if( _pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILU2 || _pack == INNER_MPTILUC ) + { + Sparse::Matrix & A = *(Sparse::Matrix *)matrix_data; + //IterativeMethod & sol = *(IterativeMethod *)solver_data; + INMOST_DATA_ENUM_TYPE lbeg, lend, l, iter; + INMOST_DATA_REAL_TYPE norm, sum[2], norm_prev, lambda_min, lambda_max; + bool diverged_max = false, diverged_min = false; + info.GetLocalRegion(info.GetRank(),lbeg,lend); + Sparse::Vector v, Av; + info.PrepareVector(v); + info.PrepareVector(Av); + //Set v to random + norm = 0; + for(l = lbeg; l < lend; ++l) + { + v[l] = rand()/static_cast(RAND_MAX); + norm += v[l]*v[l]; + } + info.Integrate(&norm,1); + norm_prev = 0.0; + norm = sqrt(norm); + for(l = lbeg; l < lend; ++l) v[l] /= norm; + //Compute maximum eigenvalue + iter = 0; + while( fabs((norm-norm_prev)/norm) > tol && iter < maxiter) + { + info.Update(v); +#if defined(USE_OMP) +#pragma omp parallel +#endif + A.MatVec(1.0,v,0.0,Av); + norm_prev = norm; + sum[0] = sum[1] = 0.0; + for(l = lbeg; l < lend; ++l) + { + sum[0] += v[l]*Av[l]; + sum[1] += v[l]*v[l]; + } + info.Integrate(sum,2); + norm = fabs(sum[0])/sum[1]; + for(l = lbeg; l < lend; ++l) v[l] = Av[l]/norm; +#if defined(PRINT_CONDEST) + std::cout << "iteration " << iter << " norm " << norm << std::endl; +#endif + iter++; + } +#if defined(PRINT_CONDEST) + std::cout << "lambda_max " << norm << std::endl; +#endif + if( iter == maxiter ) + { + diverged_max = true; + std::cout << "Max not converged" << std::endl; + } + lambda_max = norm; + //Set v to random + norm = 0; + for(l = lbeg; l < lend; ++l) + { + v[l] = rand()/static_cast(RAND_MAX); + norm += v[l]*v[l]; + } + info.Integrate(&norm,1); + norm_prev = 0.0; + norm = sqrt(norm); + for(l = lbeg; l < lend; ++l) v[l] /= norm; + //Compute minimal eigenvalue + iter = 0; + while( fabs((norm-norm_prev)/norm) > tol && iter < maxiter) + { + info.Update(v); + Solve(v,Av); + norm_prev = norm; + sum[0] = sum[1] = 0; + for(l = lbeg; l < lend; ++l) + { + sum[0] += v[l]*Av[l]; + sum[1] += v[l]*v[l]; + } + info.Integrate(sum,2); + norm = fabs(sum[0])/sum[1]; + for(l = lbeg; l < lend; ++l) v[l] = Av[l]/norm; +#if defined(PRINT_CONDEST) + std::cout << "iteration " << iter << " norm " << norm << "\t\t" << std::endl; +#endif + iter++; + } +#if defined(PRINT_CONDEST) + std::cout << "lambda_min " << 1.0/norm << std::endl; +#endif + if( iter == maxiter ) + { + diverged_min = true; + std::cout << "Min not converged" << std::endl; + } + lambda_min = 1.0/norm; + if( diverged_max || diverged_min ) + return 1.0e+100; +#if defined(PRINT_CONDEST) + std::cout << "Condest: " << lambda_max /lambda_min << std::endl; +#endif + return lambda_max/lambda_min; + } + else + { + throw -1; //other packages are not supported yet + } + } +#else + INMOST_DATA_REAL_TYPE Solver::Condest(INMOST_DATA_REAL_TYPE tol, INMOST_DATA_ENUM_TYPE maxiter) + { + if( matrix_data == NULL ) throw MatrixNotSetInSolver; + if( _pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILU2 || _pack == INNER_MPTILUC ) + { + Sparse::Matrix & A = *(Sparse::Matrix *)matrix_data; + //IterativeMethod & sol = *(IterativeMethod *)solver_data; + INMOST_DATA_ENUM_TYPE lbeg, lend, l, iter; + INMOST_DATA_REAL_TYPE norm, norm_prev, lambda_min, lambda_max; + bool diverged_max = false, diverged_min = false; + info.GetLocalRegion(info.GetRank(),lbeg,lend); + Sparse::Vector v, Av; + info.PrepareVector(v); + info.PrepareVector(Av); + //Set v to random + norm = 0; + for(l = lbeg; l < lend; ++l) + { + v[l] = rand()/static_cast(RAND_MAX); + norm += v[l]*v[l]; + } + info.Integrate(&norm,1); + norm_prev = 0.0; + norm = sqrt(norm); + for(l = lbeg; l < lend; ++l) v[l] /= norm; + //Compute maximum eigenvalue + iter = 0; + while( fabs(norm-norm_prev)/norm > tol && iter < maxiter) + { + info.Update(v); +#if defined(USE_OMP) +#pragma omp parallel +#endif + A.MatVec(1.0,v,0.0,Av); + v.Swap(Av); + norm_prev = norm; + norm = 0.0; + for(l = lbeg; l < lend; ++l) norm += v[l]*v[l]; + info.Integrate(&norm,1); + norm = sqrt(norm); + for(l = lbeg; l < lend; ++l) v[l] /= norm; +#if defined(PRINT_CONDEST) + std::cout << "iteration " << iter << " norm " << norm << std::endl; +#endif + iter++; + } +#if defined(PRINT_CONDEST) + std::cout << "lambda_max " << norm << std::endl; +#endif + if( iter == maxiter ) + { + norm = std::max(norm,norm_prev); + //diverged_max = true; + //std::cout << "Max not converged" << std::endl; + } + lambda_max = norm; + //Set v to random + norm = 0; + for(l = lbeg; l < lend; ++l) + { + v[l] = rand()/static_cast(RAND_MAX); + norm += v[l]*v[l]; + } + info.Integrate(&norm,1); + norm_prev = 0.0; + norm = sqrt(norm); + for(l = lbeg; l < lend; ++l) v[l] /= norm; + //Compute minimal eigenvalue + iter = 0; + while( fabs(norm-norm_prev)/norm > tol && iter < maxiter) + { + info.Update(v); + Solve(v,Av); + v.Swap(Av); + norm_prev = norm; + norm = 0.0; + for(l = lbeg; l < lend; ++l) norm += v[l]*v[l]; + info.Integrate(&norm,1); + norm = sqrt(norm); + for(l = lbeg; l < lend; ++l) v[l] /= norm; +#if defined(PRINT_CONDEST) + std::cout << "iteration " << iter << " norm " << norm << "\t\t" << std::endl; +#endif + iter++; + } +#if defined(PRINT_CONDEST) + std::cout << "lambda_min " << 1.0/norm << std::endl; +#endif + if( iter == maxiter ) + { + norm = std::max(norm,norm_prev); + //diverged_min = true; + //std::cout << "Min not converged" << std::endl; + } + lambda_min = 1.0/norm; + if( diverged_max || diverged_min ) + return 1.0e+100; +#if defined(PRINT_CONDEST) + std::cout << "Condest: " << lambda_max /lambda_min << std::endl; +#endif + return lambda_max/lambda_min; + } + else + { + throw -1; //other packages are not supported yet + } + } +#endif + bool Solver::Solve(Sparse::Vector & RHS, Sparse::Vector & SOL) + { + //check the data + if( matrix_data == NULL ) throw MatrixNotSetInSolver; + if( RHS.GetCommunicator() != comm || SOL.GetCommunicator() != comm ) throw DifferentCommunicatorInSolver; + INMOST_DATA_ENUM_TYPE vbeg,vend; + RHS.GetInterval(vbeg,vend); + if( RHS.Size() != SOL.Size() ) + { + if( SOL.Size() == 0 ) + { + SOL.SetInterval(vbeg,vend); + for(Sparse::Vector::iterator ri = SOL.Begin(); ri != SOL.End(); ++ri) *ri = 0.0; + } + else throw InconsistentSizesInSolver; + } + //run the solver +#if defined(USE_SOLVER_PETSC) + if( _pack == PETSc ) + { + if( rhs_data == NULL ) + VectorInitDataPetsc(&rhs_data,RHS.GetCommunicator(),RHS.GetName().c_str()); + VectorPreallocatePetsc(rhs_data,local_size,global_size); + + if( solution_data == NULL ) + VectorInitDataPetsc(&solution_data,SOL.GetCommunicator(),SOL.GetName().c_str()); + VectorPreallocatePetsc(solution_data,local_size,global_size); + + + int * positions = new int[local_size]; + double * values = new double[local_size]; + { + unsigned k = 0; + for(Sparse::Vector::iterator it = RHS.Begin(); it != RHS.End(); ++it) + { + positions[k] = vbeg+k; + values[k] = *it; + k++; + } + VectorFillPetsc(rhs_data,local_size,positions,values); + VectorFinalizePetsc(rhs_data); + + k = 0; + for(Sparse::Vector::iterator it = SOL.Begin(); it != SOL.End(); ++it) + { + values[k] = *it; + k++; + } + VectorFillPetsc(solution_data,local_size,positions,values); + VectorFinalizePetsc(solution_data); + } + if( petsc_database_file == "" ) //set parameters if no file is set + { + SolverSetTolerancesPetsc(solver_data,relative_tolerance,absolute_tolerance,divergence_tolerance,maximum_iterations); + } + bool result = SolverSolvePetsc(solver_data,rhs_data,solution_data); + if( result ) + { + VectorLoadPetsc(solution_data,local_size,positions,values); + unsigned k = 0; + for(Sparse::Vector::iterator it = SOL.Begin(); it != SOL.End(); ++it) + { + *it = values[k]; + k++; + } + } + delete [] positions; + delete [] values; + last_resid = SolverResidualNormPetsc(solver_data); + last_it = SolverIterationNumberPetsc(solver_data); + return_reason = std::string(SolverConvergedReasonPetsc(solver_data)); + return result; + } +#endif +#if defined(USE_SOLVER_ANI) + if( _pack == ANI ) + { + if( rhs_data == NULL ) + VectorInitDataAni(&rhs_data,RHS.GetCommunicator(),RHS.GetName().c_str()); + VectorPreallocateAni(rhs_data,local_size); + + if( solution_data == NULL ) + VectorInitDataAni(&solution_data,SOL.GetCommunicator(),SOL.GetName().c_str()); + VectorPreallocateAni(solution_data,local_size); + { + VectorFillAni(rhs_data,&RHS[vbeg]); + VectorFinalizeAni(rhs_data); + + VectorFillAni(solution_data,&SOL[vbeg]); + VectorFinalizeAni(solution_data); + } + bool result = SolverSolveAni(solver_data,rhs_data,solution_data); + if( result ) VectorLoadAni(solution_data,&SOL[vbeg]); + last_resid = SolverResidualNormAni(solver_data); + last_it = SolverIterationNumberAni(solver_data); + return_reason = "Unspecified for ANI"; + return result; + } +#endif +#if defined(HAVE_SOLVER_FCBIILU2) + if( _pack == FCBIILU2 ) + { + if( rhs_data == NULL ) + VectorInitDataFcbiilu2(&rhs_data,RHS.GetCommunicator(),RHS.GetName().c_str()); + VectorPreallocateFcbiilu2(rhs_data,local_size); + + if( solution_data == NULL ) + VectorInitDataFcbiilu2(&solution_data,SOL.GetCommunicator(),SOL.GetName().c_str()); + VectorPreallocateFcbiilu2(solution_data,local_size); + { + VectorFillFcbiilu2(rhs_data,&RHS[vbeg]); + VectorFinalizeFcbiilu2(rhs_data); + + VectorFillFcbiilu2(solution_data,&SOL[vbeg]); + VectorFinalizeFcbiilu2(solution_data); + } + bool result = SolverSolveFcbiilu2(solver_data,rhs_data,solution_data); + if( result ) VectorLoadFcbiilu2(solution_data,&SOL[vbeg]); + last_resid = SolverResidualNormFcbiilu2(solver_data); + last_it = SolverIterationNumberFcbiilu2(solver_data); + //return_reason = std::string(SolverConvergedReasonFcbiilu2(solver_data)); + return_reason = "Unspecified for FCBIILU2"; + return result; + } +#endif +#if defined(HAVE_SOLVER_K3BIILU2) + if( _pack == K3BIILU2 ) + { + if( rhs_data == NULL ) + VectorInitDataK3biilu2(&rhs_data,RHS.GetCommunicator(),RHS.GetName().c_str()); + VectorPreallocateK3biilu2(rhs_data,local_size); + + if( solution_data == NULL ) + VectorInitDataK3biilu2(&solution_data,SOL.GetCommunicator(),SOL.GetName().c_str()); + VectorPreallocateK3biilu2(solution_data,local_size); + { + VectorFillK3biilu2(rhs_data,&RHS[vbeg]); + VectorFinalizeK3biilu2(rhs_data); + + VectorFillK3biilu2(solution_data,&SOL[vbeg]); + VectorFinalizeK3biilu2(solution_data); + } + bool result = SolverSolveK3biilu2(solver_data,rhs_data,solution_data); + if( result ) VectorLoadK3biilu2(solution_data,&SOL[vbeg]); + last_resid = SolverResidualNormK3biilu2(solver_data); + last_it = SolverIterationNumberK3biilu2(solver_data); + //return_reason = std::string(SolverConvergedReasonK3biilu2(solver_data)); + return_reason = "Unspecified for K3BIILU2"; + return result; + } +#endif +#if defined(USE_SOLVER_TRILINOS) + if(_pack == Trilinos_Aztec || + _pack == Trilinos_ML || + _pack == Trilinos_Ifpack) + { + assert(matrix_data); + std::string name = static_cast *>(solver_data)->first; + Epetra_LinearProblem * problem = &static_cast *>(solver_data)->second; + Epetra_CrsMatrix * Matrix = static_cast(matrix_data); + Epetra_Vector VectorRHS(View,Matrix->Map(),&*RHS.Begin()); + Epetra_Vector VectorSOL(View,Matrix->Map(),&*SOL.Begin()); + problem->SetRHS(&VectorRHS); + problem->SetLHS(&VectorSOL); + std::string specific_database_file = ""; + if( _pack == Trilinos_Aztec ) + specific_database_file = trilinos_aztec_database_file; + else if( _pack == Trilinos_ML ) + specific_database_file = trilinos_ml_database_file; + else if( _pack == Trilinos_Ifpack ) + specific_database_file = trilinos_ifpack_database_file; + + bool have_params = specific_database_file != ""; + const Teuchos::RCP top_level_params = Teuchos::createParameterList(); + Teuchos::ParameterList local_list; + if( have_params ) + { + Teuchos::updateParametersFromXmlFileAndBroadcast(specific_database_file,top_level_params.ptr(),Teuchos::MpiComm(Teuchos::opaqueWrapper(RHS.GetCommunicator()))); + //top_level_params->print(std::cout,0,true,true); + if( !top_level_params->isSublist(name) ) + have_params = false; + else + { + local_list = top_level_params->sublist(name); + //std::cout << "Got local list for " << name << std::endl; + } + } + + + AztecOO AztecSolver(*problem); + + + if( have_params && local_list.isSublist("AztecOO")) + { + Teuchos::ParameterList AztecOOParams = local_list.sublist("AztecOO"); + if( AztecOOParams.isParameter("Max Iterations") ) + { + maximum_iterations = AztecOOParams.get("Max Iterations"); + //std::cout << "Got maximum iterations " << maximum_iterations << std::endl; + } + if( AztecOOParams.isParameter("Tolerance") ) + { + relative_tolerance = AztecOOParams.get("Tolerance"); + //std::cout << "Got tolerance " << relative_tolerance << std::endl; + } + if( AztecOOParams.isSublist("AztecOO Settings") ) + { + AztecSolver.SetParameters(AztecOOParams.sublist("AztecOO Settings")); + //std::cout << "Submit Aztec settings" << std::endl; + } + } + else + { + AztecSolver.SetAztecOption(AZ_diagnostics,AZ_none); + AztecSolver.SetAztecOption(AZ_output,AZ_none); + AztecSolver.SetAztecOption(AZ_solver,AZ_bicgstab); + AztecSolver.SetAztecOption(AZ_overlap,additive_schwartz_overlap); + } + + void * precinfo = NULL; + if( _pack == Trilinos_Aztec ) + { + if( !have_params ) + { + AztecSolver.SetAztecParam(AZ_drop,preconditioner_drop_tolerance); + AztecSolver.SetAztecParam(AZ_ilut_fill,preconditioner_fill_level); + //AztecSolver.SetAztecOption(AZ_solver,AZ_tfqmr); + //AztecSolver.SetAztecOption(AZ_precond,AZ_Neumann); + //AztecSolver.SetAztecOption(AZ_poly_ord,3); + } + else + { + //should be set automatically + } + } + else if( _pack == Trilinos_ML ) + { + Teuchos::ParameterList List; + if( have_params && local_list.isSublist("ML") && local_list.sublist("ML").isSublist("ML Settings") ) + { + List = local_list.sublist("ML").sublist("ML Settings"); + } + else + { + ML_Epetra::SetDefaults("SA",List); + List.set("max levels",6); + List.set("increasing or decreasing","decreasing"); + //List.set("aggreagation: type", "MIS"); + //List.set("coarse: type", "Amesos-KLU"); + } + ML_Epetra::MultiLevelPreconditioner * Prec = new ML_Epetra::MultiLevelPreconditioner(*Matrix,List,true); + AztecSolver.SetPrecOperator(Prec); + precinfo = Prec; + } + else if( _pack == Trilinos_Ifpack ) + { + Ifpack * Factory = new Ifpack(); + Ifpack_Preconditioner * Prec; + std::string PrecType = "ILU"; + if( have_params && local_list.isSublist("Ifpack") ) + { + Teuchos::ParameterList ifpacklist = local_list.sublist("Ifpack"); + if( ifpacklist.isParameter("Prec Type") ) + { + PrecType = ifpacklist.get("Prec Type"); + //std::cout << "Got preconditioner type " << PrecType << std::endl; + } + if( ifpacklist.isParameter("Overlap") ) + { + additive_schwartz_overlap = ifpacklist.get("Overlap"); + //std::cout << "Got overlap " << additive_schwartz_overlap << std::endl; + } + } + Prec = Factory->Create(PrecType,Matrix,additive_schwartz_overlap); + Teuchos::ParameterList List; + if( have_params && local_list.isSublist("Ifpack") && local_list.sublist("Ifpack").isSublist("Ifpack Settings") ) + { + List = local_list.sublist("Ifpack").sublist("Ifpack Settings"); + //std::cout << "Submit settings to ifpack" << std::endl; + } + else + List.set("fact: level-of-fill",static_cast(preconditioner_fill_level)); + Prec->SetParameters(List); + Prec->Initialize(); + Prec->Compute(); + AztecSolver.SetPrecOperator(Prec); + precinfo = Factory; + } + AztecSolver.Iterate(maximum_iterations,relative_tolerance); + if( _pack == Trilinos_ML ) + delete static_cast(precinfo); + else if( _pack == Trilinos_Ifpack ) + delete static_cast(precinfo); + const double * stats = AztecSolver.GetAztecStatus(); + bool ret = true; + switch(static_cast(stats[AZ_why])) + { + case AZ_normal: + return_reason = "User requested convergence criteria is satisfied."; + break; + case AZ_param: + return_reason = "User requested option is not availible."; + ret = false; + break; + case AZ_breakdown: + return_reason = "Numerical breakdown occurred."; + ret = false; + break; + case AZ_loss: + return_reason = "Numerical loss precision occurred."; + ret = false; + break; + case AZ_ill_cond: + return_reason = "The Hessenberg matrix within GMRES is illconditioned. " + "This could be caused by a number " + "of reasons. For example, the preconditioning " + "matrix could be nearly singular due to an unstable " + "factorization (note: pivoting is not implemented " + "in any of the incomplete factorizations). " + "Ill-conditioned Hessenberg matrices could also " + "arise from a singular application matrix. In this " + "case, GMRES tries to compute a least-squares " + "solution."; + ret = false; + break; + case AZ_maxits: + return_reason = "Maximum iterations taken without convergence."; + ret = false; + break; + default: + { + std::stringstream str; + str << "reason code " << static_cast(stats[AZ_why]) << " was not specified in manual by the time, reffer to Trilinos manual."; + return_reason = str.str(); + } + break; + } + last_it = AztecSolver.NumIters(); + last_resid = AztecSolver.TrueResidual(); + return ret; + } + if(_pack == Trilinos_Belos ) + { + assert(matrix_data); + std::string name = static_cast *>(solver_data)->first; + Epetra_LinearProblem * problem = &static_cast *>(solver_data)->second; + Epetra_CrsMatrix * Matrix = static_cast(matrix_data); + Epetra_Vector VectorRHS(View,Matrix->Map(),&*RHS.Begin()); + Epetra_Vector VectorSOL(View,Matrix->Map(),&*SOL.Begin()); + problem->SetRHS(&VectorRHS); + problem->SetLHS(&VectorSOL); + + bool have_params = trilinos_belos_database_file != ""; + const Teuchos::RCP top_level_params = Teuchos::createParameterList(); + if( have_params ) Teuchos::updateParametersFromXmlFileAndBroadcast(trilinos_belos_database_file,top_level_params.ptr(),Teuchos::MpiComm(Teuchos::opaqueWrapper(RHS.GetCommunicator()))); + + Teuchos::RCP List = Teuchos::rcp(new Teuchos::ParameterList); + + if( have_params && top_level_params->isSublist(name) && top_level_params->sublist(name).isSublist("Belos") ) + *List = top_level_params->sublist(name).sublist("Belos"); + else + { + List->set("Num Blocks",100); + List->set("Block Size",1); + List->set("Maximum Iterations",static_cast(maximum_iterations)); + List->set("Maximum Restarts",20); + List->set("Convergence Tolerance",static_cast(relative_tolerance)); + } + //int verbosity = Belos::Warnings + Belos::Errors + Belos::StatusTestDetails + Belos::Debug + Belos::FinalSummary + Belos::TimingDetails; + //List->set("Verbosity",verbosity); + Teuchos::RCP > Problem = + Teuchos::rcp(new Belos::LinearProblem); + Problem->setLHS(Teuchos::rcp_implicit_cast(Teuchos::rcp(&VectorSOL,false))); + Problem->setRHS(Teuchos::rcp_implicit_cast(Teuchos::rcp(&VectorRHS,false))); + Problem->setOperator(Teuchos::rcp_implicit_cast(Teuchos::rcp(Matrix,false))); + + /* + //This don't work + Teuchos::ParameterList MLList; + ML_Epetra::SetDefaults("SA",MLList); + MLList.set("max levels",6); + MLList.set("increasing or decreasing","decreasing"); + //List.set("aggreagation: type", "MIS"); + //List.set("coarse: type", "Amesos-KLU"); + ML_Epetra::MultiLevelPreconditioner * Prec = new ML_Epetra::MultiLevelPreconditioner(*Matrix,MLList,true); + Prec->ComputePreconditioner(); + Problem->setLeftPrec(Teuchos::rcp_implicit_cast(Teuchos::rcp(Prec,false))); + */ + + Problem->setProblem(); + + Teuchos::RCP< Belos::SolverManager > BelosSolver = + // Teuchos::rcp(new Belos::BlockCgSolMgr); + Teuchos::rcp(new Belos::BlockGmresSolMgr); + // Teuchos::rcp(new Belos::PseudoBlockGmresSolMgr); + BelosSolver->setParameters(List); + BelosSolver->setProblem(Problem); + Belos::ReturnType ret = BelosSolver->solve(); + last_it = BelosSolver->getNumIters(); + last_resid = BelosSolver->achievedTol(); + + //delete Prec; + + if( ret == Belos::Converged ) + { + return_reason = "Converged"; + return true; + } + else + { + std::stringstream reason_stream; + reason_stream << "Diverged "; + if( BelosSolver->isLOADetected() ) + reason_stream << "loss of accuracy detected "; + if( BelosSolver->getNumIters() >= 1000 ) + reason_stream << "maximum iteration number reached "; + if( BelosSolver->achievedTol() > 1.0e+6 ) + reason_stream << "divergence tolerance reached "; + return_reason = reason_stream.str(); + return false; + } + + } +#endif +#if defined(USE_SOLVER_SUPERLU) + if(_pack == SUPERLU ) + { + int size = MatrixSizeSuperLU(solver_data); + double * inout = new double[size]; + int * remap = MatrixRemapArraySuperLU(solver_data); + int mbeg = RHS.GetFirstIndex(), mend = RHS.GetLastIndex(); + for(int k = 0; k < mend - mbeg; ++k) if( remap[k] != -1 ) inout[remap[k]] = RHS[k+mbeg]; + bool ret = SolverSolveSuperLU(solver_data,inout); + for(int k = 0; k < mend - mbeg; ++k) if( remap[k] != -1 ) SOL[k+mbeg] = inout[remap[k]]; + delete [] inout; + last_it = 1; + last_resid = 0; + return_reason = SolverConvergedReasonSuperLU(solver_data); + return ret; + } +#endif + if(_pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILUC || _pack == INNER_MPTILU2) + { + IterativeMethod * sol = static_cast(solver_data); + + sol->EnumParameter("maxits") = maximum_iterations; + sol->RealParameter("rtol") = relative_tolerance; + sol->RealParameter("atol") = absolute_tolerance; + sol->RealParameter("divtol") = divergence_tolerance; + + bool ret = sol->Solve(RHS,SOL); + last_it = sol->GetIterations(); + last_resid = sol->GetResidual(); + return_reason = sol->GetReason(); + return ret; + } + throw NotImplemented; + } + + std::string Solver::GetReason() + { + return return_reason; + } + + INMOST_DATA_ENUM_TYPE Solver::Iterations() + { + return last_it; + } + INMOST_DATA_REAL_TYPE Solver::Residual() + { + return last_resid; + } + + INMOST_DATA_REAL_TYPE Solver::GetConditionNumberL() + { + if(_pack == INNER_MPTILUC ) + { + return static_cast(solver_data)->RealParameter(":condition_number_L"); + } + else return 0.0; + } + INMOST_DATA_REAL_TYPE Solver::GetConditionNumberU() + { + if(_pack == INNER_MPTILUC ) + { + return static_cast(solver_data)->RealParameter(":condition_number_U"); + } + else return 0.0; + } + +} +#endif + diff --git a/Source/Solver/solver_ani.cpp b/Source/Solver/old/solver_ani.cpp similarity index 100% rename from Source/Solver/solver_ani.cpp rename to Source/Solver/old/solver_ani.cpp diff --git a/Source/Solver/solver_ani.h b/Source/Solver/old/solver_ani.h similarity index 100% rename from Source/Solver/solver_ani.h rename to Source/Solver/old/solver_ani.h diff --git a/Source/Solver/solver_bcgsl.hpp b/Source/Solver/old/solver_bcgsl.hpp similarity index 100% rename from Source/Solver/solver_bcgsl.hpp rename to Source/Solver/old/solver_bcgsl.hpp diff --git a/Source/Solver/solver_ddpqiluc2.cpp b/Source/Solver/old/solver_ddpqiluc2.cpp similarity index 100% rename from Source/Solver/solver_ddpqiluc2.cpp rename to Source/Solver/old/solver_ddpqiluc2.cpp diff --git a/Source/Solver/solver_ddpqiluc2.hpp b/Source/Solver/old/solver_ddpqiluc2.hpp similarity index 100% rename from Source/Solver/solver_ddpqiluc2.hpp rename to Source/Solver/old/solver_ddpqiluc2.hpp diff --git a/Source/Solver/solver_fcbiilu2.cpp b/Source/Solver/old/solver_fcbiilu2.cpp similarity index 100% rename from Source/Solver/solver_fcbiilu2.cpp rename to Source/Solver/old/solver_fcbiilu2.cpp diff --git a/Source/Solver/solver_fcbiilu2.h b/Source/Solver/old/solver_fcbiilu2.h similarity index 100% rename from Source/Solver/solver_fcbiilu2.h rename to Source/Solver/old/solver_fcbiilu2.h diff --git a/Source/Solver/solver_ilu2.hpp b/Source/Solver/old/solver_ilu2.hpp similarity index 100% rename from Source/Solver/solver_ilu2.hpp rename to Source/Solver/old/solver_ilu2.hpp diff --git a/Source/Solver/solver_k3biilu2.cpp b/Source/Solver/old/solver_k3biilu2.cpp similarity index 100% rename from Source/Solver/solver_k3biilu2.cpp rename to Source/Solver/old/solver_k3biilu2.cpp diff --git a/Source/Solver/solver_k3biilu2.h b/Source/Solver/old/solver_k3biilu2.h similarity index 100% rename from Source/Solver/solver_k3biilu2.h rename to Source/Solver/old/solver_k3biilu2.h diff --git a/Source/Solver/solver_mtilu2.cpp b/Source/Solver/old/solver_mtilu2.cpp similarity index 100% rename from Source/Solver/solver_mtilu2.cpp rename to Source/Solver/old/solver_mtilu2.cpp diff --git a/Source/Solver/solver_mtilu2.hpp b/Source/Solver/old/solver_mtilu2.hpp similarity index 100% rename from Source/Solver/solver_mtilu2.hpp rename to Source/Solver/old/solver_mtilu2.hpp diff --git a/Source/Solver/solver_mtiluc2.cpp b/Source/Solver/old/solver_mtiluc2.cpp similarity index 100% rename from Source/Solver/solver_mtiluc2.cpp rename to Source/Solver/old/solver_mtiluc2.cpp diff --git a/Source/Solver/solver_mtiluc2.hpp b/Source/Solver/old/solver_mtiluc2.hpp similarity index 100% rename from Source/Solver/solver_mtiluc2.hpp rename to Source/Solver/old/solver_mtiluc2.hpp diff --git a/Source/Solver/solver_petsc.cpp b/Source/Solver/old/solver_petsc.cpp similarity index 100% rename from Source/Solver/solver_petsc.cpp rename to Source/Solver/old/solver_petsc.cpp diff --git a/Source/Solver/solver_petsc.h b/Source/Solver/old/solver_petsc.h similarity index 100% rename from Source/Solver/solver_petsc.h rename to Source/Solver/old/solver_petsc.h diff --git a/Source/Solver/solver_prototypes.hpp b/Source/Solver/old/solver_prototypes.hpp similarity index 100% rename from Source/Solver/solver_prototypes.hpp rename to Source/Solver/old/solver_prototypes.hpp diff --git a/Source/Solver/solver_superlu.cpp b/Source/Solver/old/solver_superlu.cpp similarity index 100% rename from Source/Solver/solver_superlu.cpp rename to Source/Solver/old/solver_superlu.cpp diff --git a/Source/Solver/solver_superlu.h b/Source/Solver/old/solver_superlu.h similarity index 100% rename from Source/Solver/solver_superlu.h rename to Source/Solver/old/solver_superlu.h diff --git a/Source/Solver/old/sparse.cpp b/Source/Solver/old/sparse.cpp new file mode 100644 index 0000000..943b5af --- /dev/null +++ b/Source/Solver/old/sparse.cpp @@ -0,0 +1,1260 @@ +#define _CRT_SECURE_NO_WARNINGS +#include "inmost_sparse.h" +#include +#include + +namespace INMOST +{ + namespace Sparse + { + +#if defined(USE_SOLVER) || defined(USE_AUTODIFF) + bool _hasRowEntryType = false; + + INMOST_MPI_Type RowEntryType = INMOST_MPI_DATATYPE_NULL; + + INMOST_MPI_Type GetRowEntryType() {return RowEntryType;} + + bool HaveRowEntryType() {return _hasRowEntryType;} + + void CreateRowEntryType() + { +#if defined(USE_MPI) + if( !HaveRowEntryType() ) + { + int ierr; + MPI_Datatype type[3] = { INMOST_MPI_DATA_ENUM_TYPE, INMOST_MPI_DATA_REAL_TYPE, MPI_UB}; + int blocklen[3] = { 1, 1, 1 }; + MPI_Aint disp[3]; + disp[0] = offsetof(Sparse::Row::entry,first); + disp[1] = offsetof(Sparse::Row::entry,second); + disp[2] = sizeof(Sparse::Row::entry); + ierr = MPI_Type_create_struct(3, blocklen, disp, type, &RowEntryType); + if( ierr != MPI_SUCCESS ) + { + std::cout << __FILE__ << ":" << __LINE__ << "problem in MPI_Type_create_struct" << std::endl; + } + ierr = MPI_Type_commit(&RowEntryType); + if( ierr != MPI_SUCCESS ) + { + std::cout << __FILE__ << ":" << __LINE__ << "problem in MPI_Type_commit" << std::endl; + } + } +#endif + _hasRowEntryType = true; + } + + void DestroyRowEntryType() + { +#if defined(USE_MPI) + if( HaveRowEntryType() ) + { + MPI_Type_free(&RowEntryType); + RowEntryType = INMOST_MPI_DATATYPE_NULL; + } +#endif + _hasRowEntryType = false; + } + +////////class RowMerger + + RowMerger::RowMerger() : Sorted(true), Nonzeros(0) {} + + INMOST_DATA_REAL_TYPE & RowMerger::operator[] (INMOST_DATA_ENUM_TYPE pos) + { + if( LinkedList[pos+1].first != UNDEF ) return LinkedList[pos+1].second; + else + { + INMOST_DATA_ENUM_TYPE index = LinkedList.get_interval_beg(), next; + if( Sorted ) + { + next = index; + while(next < pos+1) + { + index = next; + next = LinkedList[index].first; + } + assert(index < pos+1); + assert(pos+1 < next); + ++Nonzeros; + LinkedList[index].first = pos+1; + LinkedList[pos+1].first = next; + return LinkedList[pos+1].second; + } + else + { + INMOST_DATA_ENUM_TYPE index = LinkedList.get_interval_beg(); + ++Nonzeros; + LinkedList[pos+1].first = LinkedList[index].first; + LinkedList[index].first = pos+1; + return LinkedList[pos+1].second; + } + } + } + + INMOST_DATA_REAL_TYPE RowMerger::operator[] (INMOST_DATA_ENUM_TYPE pos) const + { + if( LinkedList[pos+1].first != UNDEF ) return LinkedList[pos+1].second; + else throw -1; + } + + RowMerger::RowMerger(INMOST_DATA_ENUM_TYPE interval_begin, INMOST_DATA_ENUM_TYPE interval_end, bool Sorted) + : Sorted(Sorted), Nonzeros(0), LinkedList(interval_begin,interval_end+1,Row::make_entry(UNDEF,0.0)) + { + LinkedList.begin()->first = EOL; + } + + void RowMerger::Resize(INMOST_DATA_ENUM_TYPE interval_begin, INMOST_DATA_ENUM_TYPE interval_end, bool _Sorted) + { + LinkedList.set_interval_beg(interval_begin); + LinkedList.set_interval_end(interval_end+1); + std::fill(LinkedList.begin(),LinkedList.end(),Row::make_entry(UNDEF,0.0)); + LinkedList.begin()->first = EOL; + Nonzeros = 0; + Sorted = _Sorted; + } +#if defined(USE_SOLVER) + void RowMerger::Resize(Matrix & A, bool _Sorted) + { + INMOST_DATA_ENUM_TYPE mbeg, mend; + A.GetInterval(mbeg,mend); + Resize(mbeg,mend,_Sorted); + } + + RowMerger::RowMerger(Matrix & A, bool Sorted) : Sorted(Sorted), Nonzeros(0) + { + INMOST_DATA_ENUM_TYPE mbeg, mend; + A.GetInterval(mbeg,mend); + LinkedList.set_interval_beg(mbeg); + LinkedList.set_interval_end(mend+1); + std::fill(LinkedList.begin(),LinkedList.end(),Row::make_entry(UNDEF,0.0)); + LinkedList.begin()->first = EOL; + } +#endif + + RowMerger::~RowMerger() {} + + void RowMerger::Clear() + { + INMOST_DATA_ENUM_TYPE i = LinkedList.begin()->first, j; + LinkedList.begin()->first = EOL; + while( i != EOL ) + { + j = LinkedList[i].first; + LinkedList[i].first = UNDEF; + LinkedList[i].second = 0.0; + i = j; + } + Nonzeros = 0; + } + + void RowMerger::PushRow(INMOST_DATA_REAL_TYPE coef, Row & r, bool PreSortRow) + { + if( Sorted && PreSortRow ) std::sort(r.Begin(),r.End()); + //if( Nonzeros != 0 ) printf("nnz %d link %p proc %d\n",Nonzeros,this,omp_get_thread_num()); + assert(Nonzeros == 0); //Linked list should be empty + assert(LinkedList.begin()->first == EOL); //again check that list is empty + INMOST_DATA_ENUM_TYPE index = LinkedList.get_interval_beg(); + Row::iterator it = r.Begin(), jt; + while( it != r.End() ) + { + LinkedList[index].first = it->first+1; + LinkedList[it->first+1].first = EOL; + LinkedList[it->first+1].second = it->second*coef; + index = it->first+1; + ++Nonzeros; + jt = it; + ++it; + assert(!Sorted || it == r.End() || jt->first < it->first); + } + } + + void RowMerger::AddRow(INMOST_DATA_REAL_TYPE coef, Row & r, bool PreSortRow) + { + if( Sorted && PreSortRow ) std::sort(r.Begin(),r.End()); + INMOST_DATA_ENUM_TYPE index = LinkedList.get_interval_beg(), next; + Row::iterator it = r.Begin(), jt; + while( it != r.End() ) + { + if( LinkedList[it->first+1].first != UNDEF ) + LinkedList[it->first+1].second += coef*it->second; + else if( Sorted ) + { + next = index; + while(next < it->first+1) + { + index = next; + next = LinkedList[index].first; + } + assert(index < it->first+1); + assert(it->first+1 < next); + LinkedList[index].first = it->first+1; + LinkedList[it->first+1].first = next; + LinkedList[it->first+1].second = coef*it->second; + ++Nonzeros; + } + else + { + LinkedList[it->first+1].first = LinkedList[index].first; + LinkedList[it->first+1].second = coef*it->second; + LinkedList[index].first = it->first+1; + ++Nonzeros; + } + jt = it; + ++it; + assert(!Sorted || it == r.End() || jt->first < it->first); + } + } + + void RowMerger::RetriveRow(Row & r) + { + r.Resize(Nonzeros); + INMOST_DATA_ENUM_TYPE i = LinkedList.begin()->first, k = 0; + while( i != EOL ) + { + if( LinkedList[i].second ) + { + r.GetIndex(k) = i-1; + r.GetValue(k) = LinkedList[i].second; + ++k; + } + i = LinkedList[i].first; + } + r.Resize(k); + } +////////class HessianRow + + void HessianRow::RowVec(INMOST_DATA_REAL_TYPE alpha, const Row & rU, INMOST_DATA_REAL_TYPE beta, Row & rJ) const + { + INMOST_DATA_ENUM_TYPE end = rU.Size(); + for(INMOST_DATA_ENUM_TYPE i = 0; i < end; i++) rJ.GetValue(i) *= beta; + for(INMOST_DATA_ENUM_TYPE i = 0; i < end; i++) + { + const index & ind = GetIndex(i); + if( ind.first == ind.second ) + rJ[ind.first] += alpha*rU.get_safe(ind.first)*GetValue(i); + else + { + rJ[ind.first ] += alpha*rU.get_safe(ind.second)*GetValue(i); + rJ[ind.second] += alpha*rU.get_safe(ind.first )*GetValue(i); + } + } + } + + bool HessianRow::isSorted() const + { + for(INMOST_DATA_ENUM_TYPE k = 1; k < Size(); ++k) + if( GetIndex(k) < GetIndex(k-1) ) return false; + return true; + } + + void HessianRow::MergeSortedRows(INMOST_DATA_REAL_TYPE alpha, const HessianRow & left, INMOST_DATA_REAL_TYPE beta, const HessianRow & right, HessianRow & output) + { + assert(left.isSorted()); + assert(right.isSorted()); + output.Resize(left.Size()+right.Size()); + INMOST_DATA_ENUM_TYPE i = 0, j = 0, q = 0; + while( i < left.Size() && j < right.Size() ) + { + if( left.GetIndex(i) < right.GetIndex(j) ) + { + output.GetIndex(q) = left.GetIndex(i); + output.GetValue(q) = alpha*left.GetValue(i); + ++q; + ++i; + } + else if( left.GetIndex(i) == right.GetIndex(j) ) + { + output.GetIndex(q) = left.GetIndex(i); + output.GetValue(q) = alpha*left.GetValue(i) + beta*right.GetValue(j); + ++q; + ++i; + ++j; + } + else //right is smaller + { + output.GetIndex(q) = right.GetIndex(j); + output.GetValue(q) = beta*right.GetValue(j); + ++q; + ++j; + } + } + while( i < left.Size() ) + { + if( q > 0 && (output.GetIndex(q-1) == left.GetIndex(i)) ) + output.GetValue(q-1) += alpha*left.GetValue(i); + else + { + output.GetIndex(q) = left.GetIndex(i); + output.GetValue(q) = alpha*left.GetValue(i); + ++q; + } + ++i; + } + while( j < right.Size() ) + { + if( q > 0 && (output.GetIndex(q-1) == right.GetIndex(j)) ) + output.GetValue(q-1) += beta*right.GetValue(j); + else + { + output.GetIndex(q) = right.GetIndex(j); + output.GetValue(q) = beta*right.GetValue(j); + ++q; + } + ++j; + } + output.Resize(q); + } + + void HessianRow::MergeJacobianHessian(INMOST_DATA_REAL_TYPE a, const Row & JL, const Row & JR, INMOST_DATA_REAL_TYPE b, const HessianRow & HL, INMOST_DATA_REAL_TYPE c, const HessianRow & HR, HessianRow & output) + { + // merge three sorted arrays at once + // one of the array is synthesized from JL and JR on the go + static const entry stub_entry = make_entry(make_index(ENUMUNDEF,ENUMUNDEF),0.0); + assert(JL.isSorted()); + assert(JR.isSorted()); + assert(HL.isSorted()); + assert(HR.isSorted()); + output.Resize(HL.Size()+HR.Size()+JL.Size()*JR.Size()); + INMOST_DATA_ENUM_TYPE i = 0, j = 0, k = 0, l = 0, q = 0, kk = 0, ll = 0, r; + entry candidate[3] = {stub_entry,stub_entry,stub_entry}; + if( i < HL.Size() ) + candidate[0] = make_entry(HL.GetIndex(i),b*HL.GetValue(i)); + if( j < HR.Size() ) + candidate[1] = make_entry(HR.GetIndex(j),c*HR.GetValue(j)); + if( k < JL.Size() && l < JR.Size() ) + candidate[2] = make_entry(make_index(JL.GetIndex(kk),JR.GetIndex(ll)),a*JL.GetValue(kk)*JR.GetValue(ll)); + do + { + //pick smallest + r = 0; + if( candidate[1].first < candidate[r].first ) r = 1; + if( candidate[2].first < candidate[r].first ) r = 2; + //all candidates are stub - exit + if( candidate[r].first == stub_entry.first ) break; + //record selected entry + if( q > 0 && (output.GetIndex(q-1) == candidate[r].first) ) + output.GetValue(q-1) += candidate[r].second; + else + { + output.GetIndex(q) = candidate[r].first; + output.GetValue(q) = candidate[r].second; + ++q; + } + if( r == 0 ) //update left hessian index + { + if( ++i < HL.Size() ) + candidate[0] = make_entry(HL.GetIndex(i),b*HL.GetValue(i)); + else candidate[0] = stub_entry; + } + else if( r == 1 ) //update right hessian index + { + if( ++j < HR.Size() ) + candidate[1] = make_entry(HR.GetIndex(j),c*HR.GetValue(j)); + else candidate[1] = stub_entry; + } + else //update jacobians indexes + { + if( JR.GetIndex(l) < JL.GetIndex(k) ) + { + if( ++kk == JL.Size() ) + { + ++l; + kk = k; + ll = l; + } + } + else if( JL.GetIndex(k) < JR.GetIndex(l) ) + { + if( ++ll == JR.Size() ) + { + ++k; + kk = k; + ll = l; + } + } + else //values are equal + { + if( ++ll == JR.Size() ) + { + ++k; + kk = k; + ll = l; + } + } + if( kk < JL.Size() && ll < JR.Size() ) + candidate[2] = make_entry(make_index(JL.GetIndex(kk),JR.GetIndex(ll)),a*JL.GetValue(kk)*JR.GetValue(ll)); + else + candidate[2] = stub_entry; + } + } + while(true); + output.Resize(q); + } + + void HessianRow::MergeJacobianHessian(INMOST_DATA_REAL_TYPE a, const Row & JL, const Row & JR, INMOST_DATA_REAL_TYPE b, const HessianRow & H, HessianRow & output) + { + // merge three sorted arrays at once + // one of the array is synthesized from JL and JR on the go + static const entry stub_entry = make_entry(make_index(ENUMUNDEF,ENUMUNDEF),0.0); + assert(JL.isSorted()); + assert(JR.isSorted()); + assert(H.isSorted()); + output.Resize(H.Size()+JL.Size()*JR.Size()); + INMOST_DATA_ENUM_TYPE i = 0, k = 0, l = 0, q = 0, kk = 0, ll = 0, r; + entry candidate[2] = {stub_entry,stub_entry}; + if( i < H.Size() ) + candidate[0] = make_entry(H.GetIndex(i),b*H.GetValue(i)); + if( k < JL.Size() && l < JR.Size() ) + candidate[1] = make_entry(make_index(JL.GetIndex(kk),JR.GetIndex(ll)),a*JL.GetValue(kk)*JR.GetValue(ll)); + do + { + //pick smallest + r = 0; + if( candidate[1].first < candidate[r].first ) r = 1; + //all candidates are stub - exit + if( candidate[r].first == stub_entry.first ) break; + //record selected entry + if( q > 0 && (output.GetIndex(q-1) == candidate[r].first) ) + output.GetValue(q-1) += candidate[r].second; + else + { + output.GetIndex(q) = candidate[r].first; + output.GetValue(q) = candidate[r].second; + ++q; + } + if( r == 0 ) //update left hessian index + { + if( ++i < H.Size() ) + candidate[0] = make_entry(H.GetIndex(i),b*H.GetValue(i)); + else candidate[0] = stub_entry; + } + else //update jacobians indexes + { + if( JR.GetIndex(l) < JL.GetIndex(k) ) + { + if( ++kk == JL.Size() ) + { + ++l; + kk = k; + ll = l; + } + } + else if( JL.GetIndex(k) < JR.GetIndex(l) ) + { + if( ++ll == JR.Size() ) + { + ++k; + kk = k; + ll = l; + } + } + else //values are equal + { + if( ++ll == JR.Size() ) + { + ++k; + kk = k; + ll = l; + } + } + if( kk < JL.Size() && ll < JR.Size() ) + candidate[1] = make_entry(make_index(JL.GetIndex(kk),JR.GetIndex(ll)),a*JL.GetValue(kk)*JR.GetValue(ll)); + else + candidate[1] = stub_entry; + } + } + while(true); + output.Resize(q); + } + +////////class Row +#if defined(USE_SOLVER) + INMOST_DATA_REAL_TYPE Row::RowVec(Vector & x) const + { + INMOST_DATA_REAL_TYPE ret = 0; + INMOST_DATA_ENUM_TYPE end = Size(); + for(INMOST_DATA_ENUM_TYPE i = 0; i < end; i++) ret = ret + x[GetIndex(i)]*GetValue(i); + return ret; + } +#endif //USE_SOLVER + bool Row::isSorted() const + { + for(INMOST_DATA_ENUM_TYPE k = 1; k < Size(); ++k) + if( GetIndex(k) < GetIndex(k-1) ) return false; + return true; + } + void Row::MergeSortedRows(INMOST_DATA_REAL_TYPE alpha, const Row & left, INMOST_DATA_REAL_TYPE beta, const Row & right, Row & output) + { + assert(left.isSorted()); + assert(right.isSorted()); + output.Resize(left.Size()+right.Size()); + INMOST_DATA_ENUM_TYPE i = 0, j = 0, q = 0; + while( i < left.Size() && j < right.Size() ) + { + if( left.GetIndex(i) < right.GetIndex(j) ) + { + output.GetIndex(q) = left.GetIndex(i); + output.GetValue(q) = alpha*left.GetValue(i); + ++q; + ++i; + } + else if( left.GetIndex(i) == right.GetIndex(j) ) + { + output.GetIndex(q) = left.GetIndex(i); + output.GetValue(q) = alpha*left.GetValue(i) + beta*right.GetValue(j); + ++q; + ++i; + ++j; + } + else //right is smaller + { + output.GetIndex(q) = right.GetIndex(j); + output.GetValue(q) = beta*right.GetValue(j); + ++q; + ++j; + } + } + while( i < left.Size() ) + { + if( q > 0 && (output.GetIndex(q-1) == left.GetIndex(i)) ) + output.GetValue(q-1) += alpha*left.GetValue(i); + else + { + output.GetIndex(q) = left.GetIndex(i); + output.GetValue(q) = alpha*left.GetValue(i); + ++q; + } + ++i; + } + while( j < right.Size() ) + { + if( q > 0 && (output.GetIndex(q-1) == right.GetIndex(j)) ) + output.GetValue(q-1) += beta*right.GetValue(j); + else + { + output.GetIndex(q) = right.GetIndex(j); + output.GetValue(q) = beta*right.GetValue(j); + ++q; + } + ++j; + } + output.Resize(q); + } +#endif //defined(USE_SOLVER) || defined(USE_AUTODIFF) + + +#if defined(USE_SOLVER) +////////class Vector + Vector::Vector(std::string _name, INMOST_DATA_ENUM_TYPE start, INMOST_DATA_ENUM_TYPE end, INMOST_MPI_Comm _comm) :data(start,end) + { + comm = _comm; + name = _name; + is_parallel = false; + } + + Vector::Vector(const Vector & other) : data(other.data) + { + comm = other.comm; + name = other.name; + is_parallel = other.is_parallel; + } + + Vector & Vector::operator =(Vector const & other) + { + comm = other.comm; + data = other.data; + name = other.name; + is_parallel = other.is_parallel; + return *this; + } + + Vector::~Vector() + { + } + + void Vector::Load(std::string file, INMOST_DATA_ENUM_TYPE mbeg, INMOST_DATA_ENUM_TYPE mend) + { + char str[16384]; + std::ifstream input(file.c_str()); + if( input.fail() ) throw -1; + int state = 0, k; + INMOST_DATA_ENUM_TYPE vec_size, vec_block, ind = 0; + INMOST_DATA_REAL_TYPE val; + int size = 1, rank = 0; +#if defined(USE_MPI) + int flag = 0; + MPI_Initialized(&flag); + if( flag && mend == ENUMUNDEF && mbeg == ENUMUNDEF ) + { + MPI_Comm_rank(GetCommunicator(),&rank); + MPI_Comm_size(GetCommunicator(),&size); + } +#endif + while( !input.getline(str,16384).eof() ) + { + k = 0; while( isspace(str[k]) ) k++; + if( str[k] == '%' || str[k] == '\0' ) continue; + std::istringstream istr(str+k); + switch(state) + { + case 0: + istr >> vec_size; state = 1; + vec_block = vec_size/size; + if( mbeg == ENUMUNDEF ) mbeg = rank*vec_block; + if( mend == ENUMUNDEF ) + { + if( rank == size-1 ) mend = vec_size; + else mend = mbeg+vec_block; + } + SetInterval(mbeg,mend); + break; + case 1: + istr >> val; + if( ind >= mbeg && ind < mend ) data[ind] = val; + ind++; + break; + } + } + input.close(); + } + + + void Vector::Save(std::string file) + { + INMOST_DATA_ENUM_TYPE vecsize = Size(); + +#if defined(USE_MPI) + int rank = 0, size = 1; + { + MPI_Comm_rank(GetCommunicator(),&rank); + MPI_Comm_size(GetCommunicator(),&size); + INMOST_DATA_ENUM_TYPE temp = vecsize; + MPI_Allreduce(&temp,&vecsize,1,INMOST_MPI_DATA_ENUM_TYPE,MPI_SUM,GetCommunicator()); + } +#endif + std::stringstream rhs(std::ios::in | std::ios::out); + rhs << std::scientific; + rhs.precision(15); + for(iterator it = Begin(); it != End(); ++it) rhs << *it << std::endl; +#if defined(USE_MPI) && defined(USE_MPI_FILE) // Use mpi files + { + int ierr; + MPI_File fh; + MPI_Status stat; + ierr = MPI_File_open(GetCommunicator(),const_cast(file.c_str()), MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE | MPI_MODE_WRONLY, MPI_INFO_NULL, &fh); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + ierr = MPI_File_close(&fh); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + ierr = MPI_File_open(GetCommunicator(),const_cast(file.c_str()),MPI_MODE_WRONLY | MPI_MODE_CREATE,MPI_INFO_NULL,&fh); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + if( rank == 0 ) + { + std::stringstream header; + //header << "% vector " << name << std::endl; + //header << "% is written by INMOST" << std::endl; + //header << "% by MPI_File_* api" << std::endl; + header << vecsize << std::endl; + ierr = MPI_File_write_shared(fh,const_cast(header.str().c_str()),static_cast(header.str().size()),MPI_CHAR,&stat); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + } + ierr = MPI_File_write_ordered(fh,const_cast(rhs.str().c_str()),static_cast(rhs.str().size()),MPI_CHAR,&stat); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + ierr = MPI_File_close(&fh); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + } +#elif defined(USE_MPI) //USE_MPI alternative + std::string senddata = rhs.str(), recvdata; + int sendsize = static_cast(senddata.size()); + std::vector recvsize(size), displ(size); + MPI_Gather(&sendsize,1,MPI_INT,&recvsize[0],1,MPI_INT,0,GetCommunicator()); + if( rank == 0 ) + { + int totsize = recvsize[0]; + + displ[0] = 0; + for(int i = 1; i < size; i++) + { + totsize += recvsize[i]; + displ[i] = displ[i-1]+recvsize[i-1]; + } + recvdata.resize(totsize); + } + else recvdata.resize(1); //protect from dereferencing null + MPI_Gatherv(&senddata[0],sendsize,MPI_CHAR,&recvdata[0],&recvsize[0],&displ[0],MPI_CHAR,0,GetCommunicator()); + if( rank == 0 ) + { + std::fstream output(file.c_str(),std::ios::out); + output << vecsize << std::endl; + output << recvdata; + } +#else + std::fstream output(file.c_str(),std::ios::out); + //output << "% vector " << name << std::endl; + //output << "% is written by INMOST" << std::endl; + //output << "% by sequential write" << std::endl; + output << vecsize << std::endl; + output << rhs.rdbuf(); +#endif + } + +////////class Matrix + void Matrix::MatVec(INMOST_DATA_REAL_TYPE alpha, Vector & x, INMOST_DATA_REAL_TYPE beta, Vector & out) const //y = alpha*A*x + beta * y + { + INMOST_DATA_ENUM_TYPE mbeg, mend; + INMOST_DATA_INTEGER_TYPE ind, imbeg, imend; + if( out.Empty() ) + { + INMOST_DATA_ENUM_TYPE vbeg,vend; + GetInterval(vbeg,vend); + out.SetInterval(vbeg,vend); + } + //CHECK SOMEHOW FOR DEBUG THAT PROVIDED VECTORS ARE OK + //~ assert(GetFirstIndex() == out.GetFirstIndex()); + //~ assert(Size() == out.Size()); + GetInterval(mbeg,mend); + imbeg = mbeg; + imend = mend; +#if defined(USE_OMP) +#pragma omp for private(ind) +#endif + for(ind = imbeg; ind < imend; ++ind) //iterate rows of matrix + out[ind] = beta * out[ind] + alpha * (*this)[ind].RowVec(x); + // outer procedure should update out vector, if needed + } + + + void Matrix::MatVecTranspose(INMOST_DATA_REAL_TYPE alpha, Vector & x, INMOST_DATA_REAL_TYPE beta, Vector & out) const //y = alpha*A*x + beta * y + { + INMOST_DATA_ENUM_TYPE mbeg, mend; + INMOST_DATA_INTEGER_TYPE ind, imbeg, imend; + if( out.Empty() ) + { + INMOST_DATA_ENUM_TYPE vbeg,vend; + GetInterval(vbeg,vend); + out.SetInterval(vbeg,vend); + } + //CHECK SOMEHOW FOR DEBUG THAT PROVIDED VECTORS ARE OK + //~ assert(GetFirstIndex() == out.GetFirstIndex()); + //~ assert(Size() == out.Size()); + GetInterval(mbeg,mend); + imbeg = mbeg; + imend = mend; + if( beta ) for(Vector::iterator it = out.Begin(); it != out.End(); ++it) (*it) *= beta; +#if defined(USE_OMP) +#pragma omp for private(ind) +#endif + for(ind = imbeg; ind < imend; ++ind) + { + for(Row::const_iterator it = (*this)[ind].Begin(); it != (*this)[ind].End(); ++it) + out[it->first] += alpha * x[ind] * it->second; + } + // outer procedure should update out vector, if needed + } + + + Matrix::Matrix(std::string _name, INMOST_DATA_ENUM_TYPE start, INMOST_DATA_ENUM_TYPE end, INMOST_MPI_Comm _comm) + :data(start,end) + { + is_parallel = false; + comm = _comm; + SetInterval(start,end); + name = _name; + } + + Matrix::Matrix(const Matrix & other) :data(other.data) + { + comm = other.comm; + name = other.name; + } + + + Matrix & Matrix::operator =(Matrix const & other) + { + comm = other.comm; + data = other.data; + name = other.name; + return *this; + } + + Matrix::~Matrix() {} + + void Matrix::MoveRows(INMOST_DATA_ENUM_TYPE from, INMOST_DATA_ENUM_TYPE to, INMOST_DATA_ENUM_TYPE size) + { + INMOST_DATA_ENUM_TYPE i = to + size, j = from + size; + if( size > 0 && to != from ) + while( j != from ) data[--j].MoveRow(data[--i]); + } + + void HessianMatrix::MoveRows(INMOST_DATA_ENUM_TYPE from, INMOST_DATA_ENUM_TYPE to, INMOST_DATA_ENUM_TYPE size) + { + INMOST_DATA_ENUM_TYPE i = to + size, j = from + size; + if( size > 0 && to != from ) + while( j != from ) data[--j].MoveRow(data[--i]); + } + + + void Matrix::Load(std::string file, INMOST_DATA_ENUM_TYPE mbeg, INMOST_DATA_ENUM_TYPE mend) + { + char str[16384]; + std::ifstream input(file.c_str()); + if( input.fail() ) throw -1; + int state = 0, k; + INMOST_DATA_ENUM_TYPE mat_size, max_lines, row, col, mat_block; + INMOST_DATA_REAL_TYPE val; + int size = 1, rank = 0; +#if defined(USE_MPI) + int flag = 0; + MPI_Initialized(&flag); + if( flag && mend == ENUMUNDEF && mbeg == ENUMUNDEF ) + { + MPI_Comm_rank(GetCommunicator(),&rank); + MPI_Comm_size(GetCommunicator(),&size); + } +#endif + int line = 0; + while( !input.getline(str,16384).eof() ) + { + line++; + k = 0; while( isspace(str[k]) ) k++; + if( str[k] == '%' || str[k] == '\0' ) continue; + std::istringstream istr(str+k); + switch(state) + { + case 0: + istr >> mat_size >> mat_size >> max_lines; state = 1; + mat_block = mat_size/size; + if( mbeg == ENUMUNDEF ) mbeg = rank*mat_block; + if( mend == ENUMUNDEF ) + { + if( rank == size-1 ) mend = mat_size; + else mend = mbeg+mat_block; + } + SetInterval(mbeg,mend); + //~ std::cout << rank << " my interval " << mbeg << ":" << mend << std::endl; + break; + case 1: + istr >> row >> col >> val; + row--; col--; + if( row >= mbeg && row < mend ) data[row][col] = val; + break; + } + } + int nonzero = 0; + for(iterator it = Begin(); it != End(); ++it) nonzero += it->Size(); + //~ std::cout << rank << " total nonzero " << max_lines << " my nonzero " << nonzero << std::endl; + input.close(); + } + + void Matrix::Save(std::string file, const AnnotationService * text) + { + INMOST_DATA_ENUM_TYPE matsize = Size(), nonzero = 0, row = GetFirstIndex()+1; + bool have_annotation = false; + if( text && !text->Empty() ) + { + if( text->GetFirstIndex() == GetFirstIndex() && + text->GetLastIndex() == GetLastIndex()) + have_annotation = true; + else + { + std::cout << "Size of provided annotation (" << text->GetFirstIndex() << "," << text->GetLastIndex() << ")" << std::endl; + std::cout << "differs from the size of the matrix (" << GetFirstIndex() << "," << GetLastIndex() << ")" << std::endl; + } + } + for(iterator it = Begin(); it != End(); ++it) nonzero += it->Size(); +#if defined(USE_MPI) + int rank = 0, size = 1; + { + MPI_Comm_rank(GetCommunicator(),&rank); + MPI_Comm_size(GetCommunicator(),&size); + INMOST_DATA_ENUM_TYPE temp_two[2] = {matsize,nonzero}, two[2]; + MPI_Allreduce(temp_two,two,2,INMOST_MPI_DATA_ENUM_TYPE,MPI_SUM,GetCommunicator()); + matsize = two[0]; + nonzero = two[1]; + } +#endif + std::stringstream mtx(std::ios::in | std::ios::out); + mtx << std::scientific; + mtx.precision(15); + for(INMOST_DATA_ENUM_TYPE k = GetFirstIndex(); k < GetLastIndex(); ++k) + { + if( have_annotation ) + { + const std::string & str = text->GetAnnotation(k); + if( !str.empty() ) mtx << "% " << str << "\n"; + } + for(Row::iterator jt = (*this)[k].Begin(); jt != (*this)[k].End(); ++jt) + mtx << row << " " << jt->first+1 << " " << jt->second << "\n"; + ++row; + } +#if defined(USE_MPI) && defined(USE_MPI_FILE) // USE_MPI2? + { + char estring[MPI_MAX_ERROR_STRING]; + int ierr, len; + MPI_File fh; + MPI_Status stat; + ierr = MPI_File_open(GetCommunicator(),const_cast(file.c_str()), MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE | MPI_MODE_WRONLY, MPI_INFO_NULL, &fh); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + ierr = MPI_File_close(&fh); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + ierr = MPI_Barrier(GetCommunicator()); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + ierr = MPI_File_open(GetCommunicator(),const_cast(file.c_str()),MPI_MODE_WRONLY | MPI_MODE_CREATE,MPI_INFO_NULL,&fh); + if( ierr != MPI_SUCCESS ) + { + MPI_Error_string(ierr,estring,&len); + std::cout << estring << std::endl; + MPI_Abort(GetCommunicator(),__LINE__); + } + if( rank == 0 ) + { + std::stringstream header; + header << "%%MatrixMarket matrix coordinate real general" << std::endl; + header << "% matrix " << name << std::endl; + header << "% is written by INMOST" << std::endl; + header << "% by MPI_File_* api" << std::endl; + header << matsize << " " << matsize << " " << nonzero << std::endl; + //std::string header_data(header.str()); + ierr = MPI_File_write_shared(fh,const_cast(header.str().c_str()),static_cast(header.str().size()),MPI_CHAR,&stat); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + } + ierr = MPI_File_write_ordered(fh,const_cast(mtx.str().c_str()),static_cast(mtx.str().size()),MPI_CHAR,&stat); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + ierr = MPI_File_close(&fh); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + } +#elif defined(USE_MPI)//USE_MPI alternative + std::string senddata = mtx.str(), recvdata; + int sendsize = static_cast(senddata.size()); + std::vector recvsize(size), displ(size); + MPI_Gather(&sendsize,1,MPI_INT,&recvsize[0],1,MPI_INT,0,GetCommunicator()); + if( rank == 0 ) + { + int totsize = recvsize[0]; + + displ[0] = 0; + for(int i = 1; i < size; i++) + { + totsize += recvsize[i]; + displ[i] = displ[i-1]+recvsize[i-1]; + } + recvdata.resize(totsize); + } + else recvdata.resize(1); //protect from dereferencing null + MPI_Gatherv(&senddata[0],sendsize,MPI_CHAR,&recvdata[0],&recvsize[0],&displ[0],MPI_CHAR,0,GetCommunicator()); + if( rank == 0 ) + { + std::fstream output(file.c_str(),std::ios::out); + output << "%%MatrixMarket matrix coordinate real general" << std::endl; + output << "% matrix " << name << std::endl; + output << "% is written by INMOST" << std::endl; + output << "% by MPI_Gather* api and sequential write" << std::endl; + output << matsize << " " << matsize << " " << nonzero << std::endl; + output << recvdata; + } +#else + std::fstream output(file.c_str(),std::ios::out); + output << "%%MatrixMarket matrix coordinate real general" << std::endl; + output << "% matrix " << name << std::endl; + output << "% is written by INMOST" << std::endl; + output << "% by sequential write " << std::endl; + output << matsize << " " << matsize << " " << nonzero << std::endl; + output << mtx.rdbuf(); +#endif + } + + void Matrix::Swap(Matrix & other) + { + data.swap(other.data); + name.swap(other.name); + std::swap(comm,other.comm); + std::swap(is_parallel,other.is_parallel); + } + +#if defined(USE_OMP) + bool LockService::HaveLocks() const + { + return !locks.empty(); + } + bool LockService::Lock(INMOST_DATA_ENUM_TYPE row) + { + assert( !locks.empty() ); + omp_set_lock(&locks[row]); + return true; + } + bool LockService::TestLock(INMOST_DATA_ENUM_TYPE row) + { + assert( !locks.empty() ); + if( omp_test_lock(&locks[row]) ) + return true; + else + return false; + } + bool LockService::UnLock(INMOST_DATA_ENUM_TYPE row) + { + assert( !locks.empty() ); + omp_unset_lock(&locks[row]); + return true; + } + void LockService::SetInterval(INMOST_DATA_ENUM_TYPE beg, INMOST_DATA_ENUM_TYPE end) + { + if( !locks.empty() ) DestroyLocks(); + if( end != beg ) + { + locks.set_interval_beg(beg); + locks.set_interval_end(end); + for(INMOST_DATA_ENUM_TYPE k = beg; k < end; ++k) + omp_init_lock(&locks[k]); + } + } + void LockService::DestroyLocks() + { + INMOST_DATA_ENUM_TYPE kbeg,kend; + kbeg = locks.get_interval_beg(); + kend = locks.get_interval_end(); + for(INMOST_DATA_ENUM_TYPE k = kbeg; k < kend; ++k) + omp_destroy_lock(&locks[k]); + } + INMOST_DATA_ENUM_TYPE LockService::GetFirstIndex() const {return locks.get_interval_beg();} + INMOST_DATA_ENUM_TYPE LockService::GetLastIndex() const {return locks.get_interval_end();} + bool LockService::Empty() const {return locks.empty();} + void LockService::GetInterval(INMOST_DATA_ENUM_TYPE & start, INMOST_DATA_ENUM_TYPE & end) const {start = locks.get_interval_beg(); end = locks.get_interval_end();} +#else + bool LockService::HaveLocks() const {return false;} + bool LockService::Lock(INMOST_DATA_ENUM_TYPE row) {return true;} + bool LockService::TestLock(INMOST_DATA_ENUM_TYPE row) {return true;} + bool LockService::UnLock(INMOST_DATA_ENUM_TYPE row) {return true;} + void LockService::SetInterval(INMOST_DATA_ENUM_TYPE beg, INMOST_DATA_ENUM_TYPE end) {} + void LockService::DestroyLocks() {} + INMOST_DATA_ENUM_TYPE LockService::GetFirstIndex() const {return 0;} + INMOST_DATA_ENUM_TYPE LockService::GetLastIndex() const {return 0;} + bool LockService::Empty() const {return true;} + void LockService::GetInterval(INMOST_DATA_ENUM_TYPE & start, INMOST_DATA_ENUM_TYPE & end) const {start = 0; end = 0;} +#endif + + +////////class HessianMatrix + + void HessianMatrix::Load(std::string file, INMOST_DATA_ENUM_TYPE mbeg, INMOST_DATA_ENUM_TYPE mend) + { + char str[16384]; + std::ifstream input(file.c_str()); + if( input.fail() ) throw -1; + int state = 0, k; + INMOST_DATA_ENUM_TYPE mat_size, max_lines, row, coli, colj, mat_block; + INMOST_DATA_REAL_TYPE val; + int size = 1, rank = 0; +#if defined(USE_MPI) + int flag = 0; + MPI_Initialized(&flag); + if( flag && mend == ENUMUNDEF && mbeg == ENUMUNDEF ) + { + MPI_Comm_rank(GetCommunicator(),&rank); + MPI_Comm_size(GetCommunicator(),&size); + } +#endif + int line = 0; + while( !input.getline(str,16384).eof() ) + { + line++; + k = 0; while( isspace(str[k]) ) k++; + if( str[k] == '%' || str[k] == '\0' ) continue; + std::istringstream istr(str+k); + switch(state) + { + case 0: + istr >> mat_size >> mat_size >> max_lines; state = 1; + mat_block = mat_size/size; + if( mbeg == ENUMUNDEF ) mbeg = rank*mat_block; + if( mend == ENUMUNDEF ) + { + if( rank == size-1 ) mend = mat_size; + else mend = mbeg+mat_block; + } + SetInterval(mbeg,mend); + //~ std::cout << rank << " my interval " << mbeg << ":" << mend << std::endl; + break; + case 1: + istr >> row >> coli >> colj >> val; + row--; coli--; colj--; + if( row >= mbeg && row < mend ) data[row][HessianRow::make_index(coli,colj)] = val; + break; + } + } + int nonzero = 0; + for(iterator it = Begin(); it != End(); ++it) nonzero += it->Size(); + //~ std::cout << rank << " total nonzero " << max_lines << " my nonzero " << nonzero << std::endl; + input.close(); + } + + HessianMatrix::HessianMatrix(std::string _name, INMOST_DATA_ENUM_TYPE start, INMOST_DATA_ENUM_TYPE end, INMOST_MPI_Comm _comm) + :data(start,end) + { + is_parallel = false; + comm = _comm; + SetInterval(start,end); + name = _name; + } + + HessianMatrix::HessianMatrix(const HessianMatrix & other) :data(other.data) + { + comm = other.comm; + name = other.name; + } + + + HessianMatrix & HessianMatrix::operator =(HessianMatrix const & other) + { + comm = other.comm; + data = other.data; + name = other.name; + return *this; + } + + HessianMatrix::~HessianMatrix() {} + + void HessianMatrix::Save(std::string file, const AnnotationService * text) + { + INMOST_DATA_ENUM_TYPE matsize = Size(), nonzero = 0, row = GetFirstIndex()+1; + bool have_annotation = false; + if( text && !text->Empty() ) + { + if( text->GetFirstIndex() == GetFirstIndex() && + text->GetLastIndex() == GetLastIndex()) + have_annotation = true; + else + { + std::cout << "Size of provided annotation (" << text->GetFirstIndex() << "," << text->GetLastIndex() << ")" << std::endl; + std::cout << "differs from the size of the matrix (" << GetFirstIndex() << "," << GetLastIndex() << ")" << std::endl; + } + } + for(iterator it = Begin(); it != End(); ++it) nonzero += it->Size(); +#if defined(USE_MPI) + int rank = 0, size = 1; + { + MPI_Comm_rank(GetCommunicator(),&rank); + MPI_Comm_size(GetCommunicator(),&size); + INMOST_DATA_ENUM_TYPE temp_two[2] = {matsize,nonzero}, two[2]; + MPI_Allreduce(temp_two,two,2,INMOST_MPI_DATA_ENUM_TYPE,MPI_SUM,GetCommunicator()); + matsize = two[0]; + nonzero = two[1]; + } +#endif + std::stringstream mtx(std::ios::in | std::ios::out); + mtx << std::scientific; + mtx.precision(15); + for(INMOST_DATA_ENUM_TYPE k = GetFirstIndex(); k < GetLastIndex(); ++k) + { + if( have_annotation ) + { + const std::string & str = text->GetAnnotation(k); + if( !str.empty() ) mtx << "% " << str << "\n"; + } + for(HessianRow::iterator jt = (*this)[k].Begin(); jt != (*this)[k].End(); ++jt) + mtx << row << " " << jt->first.first+1 << " " << jt->first.second+1 << " " << jt->second << "\n"; + ++row; + } +#if defined(USE_MPI) && defined(USE_MPI_FILE) // USE_MPI2? + { + int ierr; + MPI_File fh; + MPI_Status stat; + ierr = MPI_File_open(GetCommunicator(),const_cast(file.c_str()), MPI_MODE_CREATE | MPI_MODE_DELETE_ON_CLOSE | MPI_MODE_WRONLY, MPI_INFO_NULL, &fh); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + ierr = MPI_File_close(&fh); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + ierr = MPI_File_open(GetCommunicator(),const_cast(file.c_str()),MPI_MODE_WRONLY | MPI_MODE_CREATE,MPI_INFO_NULL,&fh); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + if( rank == 0 ) + { + std::stringstream header; + header << "%%MatrixMarket matrix coordinate real general" << std::endl; + header << "% matrix " << name << std::endl; + header << "% is written by INMOST" << std::endl; + header << "% by MPI_File_* api" << std::endl; + header << matsize << " " << matsize << " " << nonzero << std::endl; + //std::string header_data(header.str()); + ierr = MPI_File_write_shared(fh,const_cast(header.str().c_str()),static_cast(header.str().size()),MPI_CHAR,&stat); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + } + ierr = MPI_File_write_ordered(fh,const_cast(mtx.str().c_str()),static_cast(mtx.str().size()),MPI_CHAR,&stat); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + ierr = MPI_File_close(&fh); + if( ierr != MPI_SUCCESS ) MPI_Abort(GetCommunicator(),__LINE__); + } +#elif defined(USE_MPI)//USE_MPI alternative + std::string senddata = mtx.str(), recvdata; + int sendsize = static_cast(senddata.size()); + std::vector recvsize(size), displ(size); + MPI_Gather(&sendsize,1,MPI_INT,&recvsize[0],1,MPI_INT,0,GetCommunicator()); + if( rank == 0 ) + { + int totsize = recvsize[0]; + + displ[0] = 0; + for(int i = 1; i < size; i++) + { + totsize += recvsize[i]; + displ[i] = displ[i-1]+recvsize[i-1]; + } + recvdata.resize(totsize); + } + else recvdata.resize(1); //protect from dereferencing null + MPI_Gatherv(&senddata[0],sendsize,MPI_CHAR,&recvdata[0],&recvsize[0],&displ[0],MPI_CHAR,0,GetCommunicator()); + if( rank == 0 ) + { + std::fstream output(file.c_str(),std::ios::out); + output << "%%MatrixMarket matrix coordinate real general" << std::endl; + output << "% matrix " << name << std::endl; + output << "% is written by INMOST" << std::endl; + output << "% by MPI_Gather* api and sequential write" << std::endl; + output << matsize << " " << matsize << " " << nonzero << std::endl; + output << recvdata; + } +#else + std::fstream output(file.c_str(),std::ios::out); + output << "%%MatrixMarket matrix coordinate real general" << std::endl; + output << "% matrix " << name << std::endl; + output << "% is written by INMOST" << std::endl; + output << "% by sequential write " << std::endl; + output << matsize << " " << matsize << " " << nonzero << std::endl; + output << mtx.rdbuf(); +#endif + } + + void HessianMatrix::Swap(HessianMatrix & other) + { + data.swap(other.data); + name.swap(other.name); + std::swap(comm,other.comm); + std::swap(is_parallel,other.is_parallel); + } + void HessianMatrix::MatVec(INMOST_DATA_REAL_TYPE alpha, const Matrix & U, INMOST_DATA_REAL_TYPE beta, Matrix & J) const //y = alpha*A*x + beta * y + { + INMOST_DATA_ENUM_TYPE mbeg, mend; + INMOST_DATA_INTEGER_TYPE ind, imbeg, imend; + if( J.Empty() ) + { + INMOST_DATA_ENUM_TYPE vbeg,vend; + GetInterval(vbeg,vend); + J.SetInterval(vbeg,vend); + } + //CHECK SOMEHOW FOR DEBUG THAT PROVIDED VECTORS ARE OK + //~ assert(GetFirstIndex() == out.GetFirstIndex()); + //~ assert(Size() == out.Size()); + GetInterval(mbeg,mend); + imbeg = mbeg; + imend = mend; +#if defined(USE_OMP) +#pragma omp for private(ind) +#endif + for(ind = imbeg; ind < imend; ++ind) //iterate rows of matrix + (*this)[ind].RowVec(alpha,U[ind],beta,J[ind]); + // outer procedure should update J Matrix, if needed + } + + +#endif //USE_SOLVER + } +} + diff --git a/Source/Solver/refactoring/CMakeLists.txt b/Source/Solver/refactoring/CMakeLists.txt deleted file mode 100644 index 116f673..0000000 --- a/Source/Solver/refactoring/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -if(USE_SOLVER_PETSC) - add_subdirectory(solver_petsc) -endif() - - -set(HEADER - ${HEADER} - ${CMAKE_CURRENT_SOURCE_DIR}/SolverInterface.h - ${CMAKE_CURRENT_SOURCE_DIR}/SolverFactory.h - ${CMAKE_CURRENT_SOURCE_DIR}/Solver2.h) - -set(SOURCE - ${SOURCE} - ${CMAKE_CURRENT_SOURCE_DIR}/Solver2.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/SolverFactory.cpp) - -set(HEADER ${HEADER} PARENT_SCOPE) -set(SOURCE ${SOURCE} PARENT_SCOPE) \ No newline at end of file diff --git a/Source/Solver/refactoring/Solver2.cpp b/Source/Solver/refactoring/Solver2.cpp deleted file mode 100644 index 78d4e3f..0000000 --- a/Source/Solver/refactoring/Solver2.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// -// Created by Dmitri Bagaev on 22.09.16. -// - -#include -#include -#include "Solver2.h" - -namespace INMOST { - - int *Solver2::argc = NULL; - char ***Solver2::argv = NULL; - const char *Solver2::database = NULL; - bool Solver2::is_initialized = false; - bool Solver2::is_finalized = false; - - Solver2::Solver2(std::string solverName, std::string prefix, INMOST_MPI_Comm _comm) { - this->solver = SolverFactory::getSolver(solverName); - this->prefix = prefix; - - solver->SetCommunicator(_comm); - std::string solverDatabasePath = Solver2::parseDatabase(solverName); - solver->Initialize(argc, argv, solverDatabasePath.c_str(), prefix); - } - - Solver2::Solver2(const Solver2 &other) { - this->solver = SolverFactory::copySolver(other.solver); - this->prefix = other.prefix; - - solver->SetCommunicator(other.solver->GetCommunicator()); - std::string solverDatabasePath = Solver2::parseDatabase(solver->SolverName()); - solver->Initialize(argc, argv, solverDatabasePath.c_str(), prefix); - } - - Solver2& Solver2::operator=(const Solver2& other) { - if( this != &other ) { - this->solver->SetCommunicator(other.solver->GetCommunicator()); - this->prefix = other.prefix; - this->solver->Assign(other.solver); - } - return *this; - } - - void Solver2::Initialize(int *argc, char ***argv, const char *database) { - Solver2::argc = argc; - Solver2::argv = argv; - Solver2::database = database; - Solver2::is_initialized = true; - Solver2::is_finalized = false; - Sparse::CreateRowEntryType(); - //Register all available solvers -#if defined(USE_SOLVER_PETSC) - SolverFactory::registerSolver("petsc"); -#endif - } - - void Solver2::SetMatrix(Sparse::Matrix & A, bool ModifiedPattern, bool OldPreconditioner) { - solver->SetMatrix(A, ModifiedPattern, OldPreconditioner); - } - - bool Solver2::Solve(INMOST::Sparse::Vector & RHS, INMOST::Sparse::Vector & SOL) { - if( !solver->isMatrixSet()) throw MatrixNotSetInSolver; - if( RHS.GetCommunicator() != solver->GetCommunicator() || SOL.GetCommunicator() != solver->GetCommunicator()) throw DifferentCommunicatorInSolver; - INMOST_DATA_ENUM_TYPE vbeg,vend; - RHS.GetInterval(vbeg,vend); - if( RHS.Size() != SOL.Size() ) - { - if( SOL.Size() == 0 ) - { - SOL.SetInterval(vbeg,vend); - for(Sparse::Vector::iterator ri = SOL.Begin(); ri != SOL.End(); ++ri) *ri = 0.0; - } - else throw InconsistentSizesInSolver; - } - return solver->Solve(RHS, SOL); - } - - void Solver2::Finalize() { - Sparse::DestroyRowEntryType(); - Solver2::is_finalized = true; - Solver2::is_initialized = false; - } - - bool Solver2::isInitialized() { - return is_initialized; - } - - bool Solver2::isFinalized() { - return is_finalized; - } - - const INMOST_DATA_ENUM_TYPE Solver2::Iterations() const { - return solver->Iterations(); - } - - const INMOST_DATA_REAL_TYPE Solver2::Residual() const { - return solver->Residual(); - } - - const std::string Solver2::ReturnReason() const { - return solver->ReturnReason(); - } - - std::string Solver2::SolverName() const { - return solver->SolverName(); - } - - std::string Solver2::SolverPrefix() const { - return prefix; - } - - Solver2::~Solver2() { - solver->Finalize(); - delete solver; - } - - std::string Solver2::parseDatabase(std::string solverName) { - const char *name = solverName.c_str(); - if( database != NULL ) { - FILE * f = fopen(database, "r"); - if (f != NULL) { - char str[4096]; - while( !feof(f) && fgets(str,4096,f)) { - int k = 0, l; - for(k = 0; k < (int)strlen(str); ++k) { - if( str[k] == ':' ) break; - } - if( k == strlen(str) ) continue; //invalid line - for(l = 0; l < k; ++l) str[l] = tolower(str[l]); - l = (int)strlen(str)-1; // Right-trim string - while(l > 0 && isspace(str[l]) ) --l; - str[l+1] = 0; - l = k+1; - while(l < (int)strlen(str) && isspace(str[l]) ) ++l; - if( l == strlen(str) ) continue; //skip empty entry - if( !strncmp(str, name, k) ) { - return std::string(str+l); - } - } - fclose(f); - } - } - return std::string(""); - } - -} diff --git a/Source/Solver/refactoring/Solver2.h b/Source/Solver/refactoring/Solver2.h deleted file mode 100644 index 31107d4..0000000 --- a/Source/Solver/refactoring/Solver2.h +++ /dev/null @@ -1,67 +0,0 @@ -// -// Created by Dmitri Bagaev on 22.09.16. -// - -#ifndef INMOST_SOLVERCONTAINER_H -#define INMOST_SOLVERCONTAINER_H - -#include -#include "SolverInterface.h" - -#define DEFAULT_ADDITIVE_SCHWARTZ_OVERLAP 1 -#define DEFAULT_ABSOLUTE_TOLERANCE 1.0e-5 -#define DEFAULT_RELATIVE_TOLERANCE 1.0e-12 -#define DEFAULT_DIVERGENCE_TOLERANCE 1.0e+100 -#define DEFAULT_MAXIMUM_ITERATIONS 2500 -#define DEFAULT_SOLVER_GMRES_SUBSTEPS 2 -#define DEFAULT_PRECONDITIONER_DROP_TOLERANCE 0.005 -#define DEFAULT_PRECONDITIONER_REUSE_TOLERANCE 0.00005 -#define DEFAULT_PRECONDITIONER_FILL_LEVEL 3 -#define DEFAULT_PRECONDITIONER_DDPQ_TOLERANCE 0.75 -#define DEFAULT_PRECONDITIONER_REORDER_NONZEROS 1 -#define DEFAULT_PRECONDITIONER_RESCALE_ITERS 6 -#define DEFAULT_PRECONDITIONER_CONDITION_ESTIMATION 1 -#define DEFAULT_PRECONDITIONER_ADAPT_DDPQ_TOLERANCE 1 - -namespace INMOST { - - class Solver2 { - private: - static int *argc; - static char ***argv; - static const char *database; - static bool is_initialized; - static bool is_finalized; - - //Actual solver using for solving system - SolverInterface *solver; - std::string prefix; - public: - - Solver2(std::string solverName, std::string prefix = "", INMOST_MPI_Comm _comm = INMOST_MPI_COMM_WORLD); - Solver2(const Solver2& other); - Solver2& operator =(const Solver2& other); - - std::string SolverName() const; - std::string SolverPrefix() const; - - static void Initialize(int *argc, char ***argv, const char *database); - static bool isInitialized(); - static bool isFinalized(); - static void Finalize(); - - void SetMatrix(Sparse::Matrix & A, bool ModifiedPattern = true, bool OldPreconditioner = false); - bool Solve(INMOST::Sparse::Vector & RHS, INMOST::Sparse::Vector & SOL); - - const INMOST_DATA_ENUM_TYPE Iterations() const; - const INMOST_DATA_REAL_TYPE Residual() const; - const std::string ReturnReason() const; - - ~Solver2(); - - static std::string parseDatabase(std::string solverName); - }; -} - - -#endif //INMOST_SOLVERCONTAINER_H diff --git a/Source/Solver/refactoring/SolverInterface.h b/Source/Solver/refactoring/SolverInterface.h deleted file mode 100644 index 103b312..0000000 --- a/Source/Solver/refactoring/SolverInterface.h +++ /dev/null @@ -1,52 +0,0 @@ -// -// Created by Dmitri Bagaev on 22.09.16. -// - -#ifndef INMOST_SOLVERINTERFACE_H -#define INMOST_SOLVERINTERFACE_H - -#include -#include "inmost_sparse.h" - -namespace INMOST { - -class SolverInterface { -protected: - INMOST_MPI_Comm communicator; -public: - SolverInterface() {}; - SolverInterface(const SolverInterface* other) {}; - virtual void Assign(const SolverInterface* other) = 0; - - virtual void Initialize(int *argc, char ***argv, const char *parameters_file, std::string prefix) = 0; - virtual void SetMatrix(Sparse::Matrix & A, bool ModifiedPattern, bool OldPreconditioner) = 0; - virtual bool Solve(INMOST::Sparse::Vector & RHS, INMOST::Sparse::Vector & SOL) = 0; - - - virtual bool isMatrixSet() = 0; - - virtual INMOST_DATA_REAL_TYPE GetPropertyReal(std::string property) const = 0; - virtual INMOST_DATA_ENUM_TYPE GetPropertyEnum(std::string property) const = 0; - - virtual const INMOST_DATA_ENUM_TYPE Iterations() const = 0; - virtual const INMOST_DATA_REAL_TYPE Residual() const = 0; - virtual const std::string ReturnReason() const = 0; - - virtual const std::string SolverName() const = 0; - - virtual void Finalize() = 0; - virtual ~SolverInterface() {}; - - - void SetCommunicator(INMOST_MPI_Comm _communicator) { - communicator = _communicator; - } - - INMOST_MPI_Comm GetCommunicator() { - return communicator; - } -}; - -} - -#endif //INMOST_SOLVERINTERFACE_H diff --git a/Source/Solver/refactoring/solver_petsc/CMakeLists.txt b/Source/Solver/refactoring/solver_petsc/CMakeLists.txt deleted file mode 100644 index 91f9356..0000000 --- a/Source/Solver/refactoring/solver_petsc/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -set(SOURCE ${SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/new_solver_petsc.cpp) -set(SOURCE ${SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/new_solver_petsc.h) -set(SOURCE ${SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/SolverPETSC.cpp) -set(HEADER ${HEADER} ${CMAKE_CURRENT_SOURCE_DIR}/SolverPETSc.h) - -set(SOURCE ${SOURCE} PARENT_SCOPE) -set(HEADER ${HEADER} PARENT_SCOPE) \ No newline at end of file diff --git a/Source/Solver/solver.cpp b/Source/Solver/solver.cpp index c0fbeeb..28dff1f 100644 --- a/Source/Solver/solver.cpp +++ b/Source/Solver/solver.cpp @@ -1,2648 +1,933 @@ -#define _CRT_SECURE_NO_WARNINGS -#include "inmost_solver.h" -#if defined(USE_SOLVER) -#include "solver_petsc.h" -#include "solver_superlu.h" -#include "solver_ani.h" -#include "solver_ilu2.hpp" -#include "solver_ddpqiluc2.hpp" -#if defined(HAVE_SOLVER_MPTILUC2) -#include "solver_mtiluc2.hpp" -#endif -#if defined(HAVE_SOLVER_MPTILU2) -#include "solver_mtilu2.hpp" -#endif -#if defined(HAVE_SOLVER_FCBIILU2) -#include "solver_fcbiilu2.h" -#endif -#if defined(HAVE_SOLVER_K3BIILU2) -#include "solver_k3biilu2.h" -#endif -#include "solver_bcgsl.hpp" -#include -#include -#include +#include +#include +#include "SolverFactory.h" -#if defined(USE_SOLVER_TRILINOS) -#if defined(USE_MPI) -#include "Epetra_MpiComm.h" -#else -#include "Epetra_SerialComm.h" -#endif -#include "Epetra_Map.h" -#include "Epetra_Vector.h" -#include "Epetra_CrsMatrix.h" -#include "AztecOO.h" -#include "Ifpack.h" -#include "ml_include.h" -#include "ml_MultiLevelPreconditioner.h" -#include "BelosEpetraOperator.h" -#include "Teuchos_Comm.hpp" -#include "Teuchos_DefaultMpiComm.hpp" -#include "Teuchos_OpaqueWrapper.hpp" -#include "Teuchos_ParameterList.hpp" -#include "Teuchos_TestForException.hpp" -#include "Teuchos_XMLParameterListHelpers.hpp" +#include "solver_inner/solver_ilu2/SolverILU2.h" + +#if defined(USE_SOLVER_PETSC) + #include "solver_petsc/SolverPETSc.h" #endif -//#define USE_OMP -//#define KSOLVER BCGSL_solver -#define KSOLVER BCGS_solver -//#define ACCELERATED_CONDEST -//#define PRINT_CONDEST +namespace INMOST { -namespace INMOST -{ - static std::string petsc_database_file = ""; - static std::string trilinos_aztec_database_file = ""; - static std::string trilinos_ifpack_database_file = ""; - static std::string trilinos_belos_database_file = ""; - static std::string trilinos_ml_database_file = ""; - static std::string ani_database_file = ""; - static std::string fcbiilu2_database_file = ""; - static std::string k3biilu2_database_file = ""; - static std::string superlu_database_file = ""; + int *Solver::argc = NULL; + char ***Solver::argv = NULL; + const char *Solver::database = NULL; + bool Solver::is_initialized = false; + bool Solver::is_finalized = false; + Solver::Solver(std::string solverName, std::string prefix, INMOST_MPI_Comm _comm) { + this->solver = SolverFactory::getSolver(solverName); + this->prefix = prefix; + solver->SetCommunicator(_comm); + std::string solverDatabasePath = Solver::parseDatabase(solverName); + solver->Initialize(argc, argv, solverDatabasePath.c_str(), prefix); + } -#define GUARD_MPI(x) {ierr = x; if( ierr != MPI_SUCCESS ) {char str[4096]; int len; MPI_Error_string(ierr,str,&len); std::cout << #x << " not successfull: " << str << std::endl; MPI_Abort(comm,-1000);}} -#define HASH_TABLE_SIZE 2048 + Solver::Solver(const Solver &other) { + this->solver = SolverFactory::copySolver(other.solver); + this->prefix = other.prefix; - bool Solver::is_initialized = false; - bool Solver::is_finalized = false; + solver->SetCommunicator(other.solver->GetCommunicator()); + std::string solverDatabasePath = Solver::parseDatabase(solver->SolverName()); + solver->Initialize(argc, argv, solverDatabasePath.c_str(), prefix); + } - std::string Solver::TypeName(Type t) - { - switch(t) - { - case INNER_ILU2: return "INNER_ILU2"; - case INNER_DDPQILUC: return "INNER_DDPQILUC"; - case INNER_MPTILUC: return "INNER_MPTILUC"; - case INNER_MPTILU2: return "INNER_MPTILU2"; - case Trilinos_Aztec: return "Trilinos_Aztec"; - case Trilinos_Belos: return "Trilinos_Belos"; - case Trilinos_ML: return "Trilinos_ML"; - case Trilinos_Ifpack: return "Trilinos_Ifpack"; - case PETSc: return "PETSc"; - case ANI: return "ANI"; - case FCBIILU2: return "FCBIILU2"; - case K3BIILU2: return "K3BIILU2"; - case SUPERLU: return "SUPERLU"; + Solver& Solver::operator=(const Solver& other) { + if( this != &other ) { + this->solver->SetCommunicator(other.solver->GetCommunicator()); + this->prefix = other.prefix; + this->solver->Assign(other.solver); + } + return *this; } - return "Unknown"; - } - int comparator(const void * pa, const void *pb) - { - INMOST_DATA_ENUM_TYPE * a = (INMOST_DATA_ENUM_TYPE *)pa, * b = (INMOST_DATA_ENUM_TYPE *)pb; - return a[0] - b[0]; - } + std::string Solver::SolverName() const { + return solver->SolverName(); + } - INMOST_DATA_ENUM_TYPE binary_search_pairs(INMOST_DATA_ENUM_TYPE * link, INMOST_DATA_ENUM_TYPE size, INMOST_DATA_ENUM_TYPE find) - { - INMOST_DATA_ENUM_TYPE rcur = size >> 1, lcur = 0, mid, chk; - while( rcur >= lcur ) - { - mid = lcur + ((rcur-lcur) >> 1); - chk = mid << 1; - if( link[chk] < find ) lcur = mid+1; - else if( link[chk] > find ) rcur = mid-1; - else return chk; - } - return size; - } - void Solver::OrderInfo::Integrate(INMOST_DATA_REAL_TYPE * inout, INMOST_DATA_ENUM_TYPE num) const - { -#if defined(USE_MPI) - if( GetSize() == 1 ) return; -#if defined(USE_OMP) -#pragma omp single -#endif - { - int ierr = 0; - dynarray temp(num); - memcpy(temp.data(),inout,sizeof(INMOST_DATA_REAL_TYPE)*num); - GUARD_MPI(MPI_Allreduce(temp.data(),inout,num,INMOST_MPI_DATA_REAL_TYPE,MPI_SUM,comm)); - } -#else - (void) inout; - (void) num; -#endif - } + std::string Solver::SolverPrefix() const { + return prefix; + } - - void Solver::OrderInfo::PrepareMatrix(Sparse::Matrix & m, INMOST_DATA_ENUM_TYPE overlap) - { - have_matrix = true; - m.isParallel() = true; - INMOST_DATA_ENUM_TYPE two[2]; - INMOST_DATA_ENUM_TYPE mbeg,mend; - int initial_rank; + void Solver::Initialize(int *argc, char ***argv, const char *database) { + Solver::argc = argc; + Solver::argv = argv; + Solver::database = database; + Solver::is_initialized = true; + Solver::is_finalized = false; #if defined(USE_MPI) - int ierr = 0; - if( comm != INMOST_MPI_COMM_WORLD ) - { - MPI_Comm_free(&comm); - comm = INMOST_MPI_COMM_WORLD; - } - if( m.GetCommunicator() == INMOST_MPI_COMM_WORLD ) - comm = INMOST_MPI_COMM_WORLD; - else MPI_Comm_dup(m.GetCommunicator(), &comm); - MPI_Comm_rank(comm,&rank); - MPI_Comm_size(comm,&size); -#else - (void) overlap; - rank = 0; - size = 1; + { + int flag = 0; + int ierr = 0; + MPI_Initialized(&flag); + if (!flag) { + ierr = MPI_Init(argc,argv); + if( ierr != MPI_SUCCESS ) { + std::cout << __FILE__ << ":" << __LINE__ << "problem in MPI_Init" << std::endl; + } + } + } #endif - initial_rank = rank; - //std::vector requests; - global_overlap.resize(size*2); - global_to_proc.resize(size+1); - m.GetInterval(mbeg,mend); - global_to_proc[0] = 0; - initial_matrix_begin = mbeg; - initial_matrix_end = mend; - two[0] = mbeg; - two[1] = mend; -#if defined(USE_MPI) - GUARD_MPI(MPI_Allgather(two,2,INMOST_MPI_DATA_ENUM_TYPE,&global_overlap[0],2,INMOST_MPI_DATA_ENUM_TYPE,comm)); -#else - local_vector_begin = initial_matrix_begin = local_matrix_begin = global_overlap[0] = mbeg; - local_vector_end = initial_matrix_end = local_matrix_end = global_overlap[1] = mend; - global_to_proc[1] = mend; + //Register all available solvers + SolverFactory::registerSolver("inner_ilu2"); +#if defined(USE_SOLVER_PETSC) + SolverFactory::registerSolver("petsc"); #endif -#if defined(USE_MPI) - //reorder processors if needed - { - //starts of local indexes should appear in asscending order - bool reorder = false; - for(int k = 0; k < size-1; k++) - if( global_overlap[2*k] > global_overlap[2*(k+1)] ) - { - reorder = true; - break; - } - if( reorder ) - { - storage_type temp(size*2); - //assemble array that includes rank - for(int k = 0; k < size; ++k) - { - temp[2*k+0] = global_overlap[2*k]; - temp[2*k+1] = k; - } - //sort array - qsort(&temp[0],size,sizeof(INMOST_DATA_ENUM_TYPE)*2,comparator); - //create new group - MPI_Group oldg, newg; - MPI_Comm newcomm; - std::vector ranks(size); - for(int k = 0; k < size; ++k) - ranks[k] = temp[2*k+1]; - GUARD_MPI(MPI_Comm_group(comm,&oldg)); - GUARD_MPI(MPI_Group_incl(oldg,size,&ranks[0],&newg)); - GUARD_MPI(MPI_Comm_create(comm,newg,&newcomm)); - if( comm != INMOST_MPI_COMM_WORLD ) - { - GUARD_MPI(MPI_Comm_free(&comm)); - } - comm = newcomm; - //compute new rank - MPI_Comm_rank(comm,&rank); - //sort array pairs, so we don't need to exchange them again - qsort(&global_overlap[0],size,sizeof(INMOST_DATA_ENUM_TYPE)*2,comparator); - } - //now check that there are no overlaps of local indexes - //every mend must be equal to every mbeg - reorder = false; - for(int k = 0; k < size-1; k++) - if( global_overlap[2*k+1] != global_overlap[2*(k+1)] ) - { - //check that end is strictly greater then begin - if( global_overlap[2*k+1] < global_overlap[2*(k+1)] ) - { - if( initial_rank == 0 ) - { - std::cout << __FILE__ << ":" << __LINE__ << " Matrix index intervals are not complete:"; - std::cout << " processor " << k+0 << " interval " << global_overlap[2*(k+0)] << ":" << global_overlap[2*(k+0)+1]; - std::cout << " processor " << k+1 << " interval " << global_overlap[2*(k+1)] << ":" << global_overlap[2*(k+1)+1]; - std::cout << std::endl; - MPI_Abort(comm,-1000); - } - } - reorder = true; - } - if( reorder ) - { - storage_type old_overlap(global_overlap); - //move local bounds to get non-overlapping regions - for(int k = 0; k < size-1; k++) - while( global_overlap[2*k+1] > global_overlap[2*(k+1)] ) - { - //move bounds to equalize sizes - if( global_overlap[2*k+1] - global_overlap[2*k] < global_overlap[2*(k+1)+1] - global_overlap[2*(k+1)] ) - global_overlap[2*k+1]--; //move right bound of the current processor to left - else - global_overlap[2*(k+1)]++; //move left bound of the next processor to right - } - - //TODO: if we need to merge overlapping parts of the matrices - do it here - } - local_matrix_begin = global_overlap[2*rank+0]; - local_matrix_end = global_overlap[2*rank+1]; - for(int k = 0; k < size; k++) - global_to_proc[k+1] = global_overlap[2*k+1]; - } - MPI_Status stat; - INMOST_DATA_ENUM_TYPE ext_pos = local_matrix_end; - //may replace std::map here - small_hash global_to_local; - std::vector< std::pair > current_global_to_local; - std::vector< Sparse::Row::entry > send_row_data, recv_row_data; - std::vector< INMOST_DATA_ENUM_TYPE > send_row_sizes, recv_row_sizes; - std::vector incoming(4*size); - std::vector requests; - INMOST_DATA_ENUM_TYPE total_send = 0, total_recv = 0; - INMOST_DATA_ENUM_TYPE local_start = local_matrix_begin, local_end = local_matrix_end; - for(INMOST_DATA_ENUM_TYPE it = 0; it < overlap+1; it++) - { - total_send = 0, total_recv = 0; - current_global_to_local.clear(); - for(INMOST_DATA_ENUM_TYPE k = local_start; k < local_end; ++k) - { - Sparse::Row & r = m[k]; - INMOST_DATA_ENUM_TYPE jend = r.Size(), ind; - for(INMOST_DATA_ENUM_TYPE j = 0; j < jend; ++j) - { - ind = r.GetIndex(j); - if( ind < local_matrix_begin || ind >= local_matrix_end) - { - INMOST_DATA_ENUM_TYPE & recv_pos = global_to_local[ind]; - if( recv_pos == 0 ) //this number was not assigned yet - { - recv_pos = ext_pos++; - if( it < overlap ) current_global_to_local.push_back(std::make_pair(ind,recv_pos)); - } - } - } - } - if( it == overlap ) - current_global_to_local = global_to_local.serialize(); - std::sort(current_global_to_local.begin(),current_global_to_local.end()); - //if( !current_global_to_local.empty() ) - { - //check all the indexes that comes from other processors - //for every processor we need arrays: - // processor -> (array of index positions where to receive)) - // processor -> (array of index positions from where to send) - memset(&incoming[0],0,sizeof(INMOST_DATA_ENUM_TYPE)*size*2); - vector_exchange_recv.clear(); - vector_exchange_recv.push_back(0); - if( !current_global_to_local.empty() ) - { - INMOST_DATA_ENUM_TYPE proc_beg = GetProcessor(current_global_to_local.begin()->first), proc_end = GetProcessor(current_global_to_local.rbegin()->first)+1; - INMOST_DATA_ENUM_TYPE current_ind = 0; - for(INMOST_DATA_ENUM_TYPE proc = proc_beg; proc < proc_end; proc++) - { - bool first = true; - INMOST_DATA_ENUM_TYPE numind = static_cast(vector_exchange_recv.size() + 1); - while( current_ind < current_global_to_local.size() && current_global_to_local[current_ind].first < global_to_proc[proc+1] ) - { - INMOST_DATA_ENUM_TYPE k = current_global_to_local[current_ind].first; - if( first ) - { - vector_exchange_recv.push_back(proc); - vector_exchange_recv.push_back(1); - vector_exchange_recv.push_back(k); - first = false; - } - else - { - vector_exchange_recv[numind]++; - vector_exchange_recv.push_back(k); - } - current_ind++; - } - if( !first ) - { - incoming[proc]++; - incoming[proc+size] += vector_exchange_recv[numind]; - vector_exchange_recv[0]++; - } - } - } - - GUARD_MPI(MPI_Allreduce(&incoming[0],&incoming[2*size],size*2,INMOST_MPI_DATA_ENUM_TYPE,MPI_SUM,comm)); - //std::cout << GetRank() << " MPI_Allreduce " << __FILE__ << ":" << __LINE__ << " incoming " << incoming[size*2+rank] << " size " << incoming[size*3+rank] << std::endl; - //prepare array that helps exchanging vector values - requests.resize(2*vector_exchange_recv[0] + incoming[size*2+rank]); - INMOST_DATA_ENUM_TYPE j = 1; - for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //send rows that i want to receive - { - total_recv += vector_exchange_recv[j+1]; - GUARD_MPI(MPI_Isend(&vector_exchange_recv[j+1],1,INMOST_MPI_DATA_ENUM_TYPE,vector_exchange_recv[j],size+vector_exchange_recv[j],comm,&requests[k])); //send number of rows - GUARD_MPI(MPI_Isend(&vector_exchange_recv[j+2],vector_exchange_recv[j+1],INMOST_MPI_DATA_ENUM_TYPE,vector_exchange_recv[j],2*size+vector_exchange_recv[j],comm,&requests[k+vector_exchange_recv[0]])); //send row positions - j += vector_exchange_recv[j+1] + 2; - } + Sparse::CreateRowEntryType(); + } - recv_row_sizes.resize(incoming[size*3+rank]); - vector_exchange_send.resize(1+incoming[size*2+rank]*2+incoming[size*3+rank]); - vector_exchange_send[0] = 0; - j = 1; - for(INMOST_DATA_ENUM_TYPE k = 0; k < incoming[size*2+rank]; k++) //receive rows that others want from me - { - INMOST_DATA_ENUM_TYPE msgsize; - GUARD_MPI(MPI_Recv(&msgsize,1,INMOST_MPI_DATA_ENUM_TYPE,MPI_ANY_SOURCE,size+rank,comm,&stat)); //recv number of rows - vector_exchange_send[j++] = stat.MPI_SOURCE; - vector_exchange_send[j++] = msgsize; - //std::cout << GetRank() << " MPI_Irecv size " << msgsize << " rank " << stat.MPI_SOURCE << " tag " << 2*size+rank << __FILE__ << ":" << __LINE__ << std::endl; - GUARD_MPI(MPI_Irecv(&vector_exchange_send[j],msgsize,INMOST_MPI_DATA_ENUM_TYPE,stat.MPI_SOURCE,2*size+rank,comm,&requests[2*vector_exchange_recv[0]+k])); //recv rows - j += msgsize; - total_send += msgsize; - vector_exchange_send[0]++; - } - assert(total_send == incoming[size*3+rank]); - assert(vector_exchange_send[0] == incoming[size*2+rank]); - if( 2*vector_exchange_recv[0] + incoming[size*2+rank] > 0 ) - GUARD_MPI(MPI_Waitall(2*vector_exchange_recv[0] + incoming[size*2+rank],&requests[0],MPI_STATUSES_IGNORE)); - } - /* - else - { - vector_exchange_recv.resize(1,0); - vector_exchange_send.resize(1,0); - } - */ - if( it == overlap ) - { - //std::cout << rank << " reorder " << std::endl; - //now we need to reorder off-diagonal parts of the matrix - for(INMOST_DATA_ENUM_TYPE k = local_matrix_begin; k < local_end; ++k) - for(Sparse::Row::iterator jt = m[k].Begin(); jt != m[k].End(); ++jt) - if( global_to_local.is_present(jt->first) ) - jt->first = global_to_local[jt->first]; - else - { - assert(jt->first >= local_matrix_begin); - assert(jt->first < local_matrix_end); - } - local_vector_begin = local_matrix_begin; - local_vector_end = ext_pos; - { - // change indexes for recv array - INMOST_DATA_ENUM_TYPE i,j = 1,k; - //for(k = 0; k < GetRank(); k++) MPI_Barrier(comm); - //std::cout << "rank " << GetRank() << std::endl; - //std::cout << "recv:" << std::endl; - for(i = 0; i < vector_exchange_recv[0]; i++) - { - //std::cout << "proc " << vector_exchange_recv[j] << " size " << vector_exchange_recv[j+1] << std::endl; - j++; //skip processor number - for(k = 0; k < vector_exchange_recv[j]; ++k) - { - assert(global_to_local.is_present(vector_exchange_recv[j+k+1])); - vector_exchange_recv[j+k+1] = global_to_local[vector_exchange_recv[j+k+1]]; - assert(vector_exchange_recv[j+k+1] >= local_matrix_end); - } - j+=vector_exchange_recv[j]+1; //add vector length + size position - } - //check that indexes in send array are in local matrix bounds - //std::cout << "send:" << std::endl; -#ifndef NDEBUG - j = 1; - for(i = 0; i < vector_exchange_send[0]; i++) - { - //std::cout << "proc " << vector_exchange_send[j] << " size " << vector_exchange_send[j+1] << std::endl; - j++; //skip processor number - for(k = 0; k < vector_exchange_send[j]; ++k) - { - assert(vector_exchange_send[j+k+1] >= local_matrix_begin); - assert(vector_exchange_send[j+k+1] < local_matrix_end); - } - j+=vector_exchange_send[j]+1; //add vector length + size position - } + void Solver::Finalize() { + Sparse::DestroyRowEntryType(); +#if defined(USE_MPI) + { + int flag = 0; + MPI_Finalized(&flag); + if( !flag ) { + MPI_Finalize(); + } + } #endif - //for(k = GetRank(); k < GetSize(); k++) MPI_Barrier(comm); - } - //prepare array local->global - extended_indexes.resize(local_vector_end-local_matrix_end); - for(std::vector< std::pair >::iterator jt = current_global_to_local.begin(); jt != current_global_to_local.end(); ++jt) - extended_indexes[jt->second-local_matrix_end] = jt->first; + Solver::is_finalized = true; + Solver::is_initialized = false; + } - send_storage.resize(total_send); - recv_storage.resize(total_recv); - send_requests.resize(vector_exchange_send[0]); - recv_requests.resize(vector_exchange_recv[0]); - - } - else - { - send_row_sizes.resize(total_send); - recv_row_sizes.resize(total_recv); + bool Solver::isInitialized() { + return is_initialized; + } - INMOST_DATA_ENUM_TYPE j = 1, q = 0, f = 0, total_rows_send = 0, total_rows_recv = 0; - for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //recv sizes of rows - { - GUARD_MPI(MPI_Irecv(&recv_row_sizes[q],vector_exchange_recv[j+1],INMOST_MPI_DATA_ENUM_TYPE,vector_exchange_recv[j],3*size+vector_exchange_recv[j],comm,&requests[k])); - q += vector_exchange_recv[j+1]; - j += vector_exchange_recv[j+1]+2; - } - j = 1; - q = 0; + bool Solver::isFinalized() { + return is_finalized; + } - for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_send[0]; k++) //send sizes of rows - { - for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_send[j+1]; r++) - { - send_row_sizes[q+r] = m[vector_exchange_send[j+2+r]].Size(); - total_rows_send += m[vector_exchange_send[j+2+r]].Size(); - } - GUARD_MPI(MPI_Isend(&send_row_sizes[q],vector_exchange_send[j+1],INMOST_MPI_DATA_ENUM_TYPE,vector_exchange_send[j],3*size+rank,comm,&requests[vector_exchange_recv[0]+k])); //recv rows - //remember processor numbers here - q += vector_exchange_send[j+1]; - j += vector_exchange_send[j+1]+2; - } - send_row_data.clear(); - send_row_data.reserve(total_rows_send); + void Solver::SetMatrix(Sparse::Matrix & A, bool ModifiedPattern, bool OldPreconditioner) { + solver->SetMatrix(A, ModifiedPattern, OldPreconditioner); + } - - j = 1; - for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_send[0]; k++) //accumulate data in array - { - for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_send[j+1]; r++) - send_row_data.insert(send_row_data.end(),m[vector_exchange_send[j+2+r]].Begin(),m[vector_exchange_send[j+2+r]].End()); - j += vector_exchange_send[j+1]+2; - } + bool Solver::Solve(INMOST::Sparse::Vector & RHS, INMOST::Sparse::Vector & SOL) { + if( !solver->isMatrixSet()) throw MatrixNotSetInSolver; + if( RHS.GetCommunicator() != solver->GetCommunicator() || SOL.GetCommunicator() != solver->GetCommunicator()) throw DifferentCommunicatorInSolver; + INMOST_DATA_ENUM_TYPE vbeg,vend; + RHS.GetInterval(vbeg,vend); + if (RHS.Size() != SOL.Size()) { + if (SOL.Size() == 0) { + SOL.SetInterval(vbeg,vend); + for(Sparse::Vector::iterator ri = SOL.Begin(); ri != SOL.End(); ++ri) *ri = 0.0; + } else throw InconsistentSizesInSolver; + } + return solver->Solve(RHS, SOL); + } - - //replace by mpi_waitsome - if( vector_exchange_recv[0]+vector_exchange_send[0] > 0 ) - GUARD_MPI(MPI_Waitall(vector_exchange_recv[0]+vector_exchange_send[0],&requests[0],MPI_STATUSES_IGNORE)); + bool Solver::Clear() { + return solver->Clear(); + } - - j = 1; - q = 0; - for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //compute total size of data to receive - { - for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_recv[j+1]; r++) - total_rows_recv += recv_row_sizes[q+r]; - q += vector_exchange_recv[j+1]; - j += vector_exchange_recv[j+1]+2; - } - recv_row_data.resize(total_rows_recv); - j = 1; - q = 0; - f = 0; - for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //receive row data - { - INMOST_DATA_ENUM_TYPE local_size = 0; - for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_recv[j+1]; r++) - local_size += recv_row_sizes[q+r]; - GUARD_MPI(MPI_Irecv(&recv_row_data[f],local_size,Sparse::GetRowEntryType(),vector_exchange_recv[j],4*size+vector_exchange_recv[j],comm,&requests[k])); - q += vector_exchange_recv[j+1]; - j += vector_exchange_recv[j+1]+2; - f += local_size; - } + INMOST_DATA_REAL_TYPE Solver::GetPropertyReal(std::string property) const { + return solver->GetPropertyReal(property); + } - - j = 1; - q = 0; - f = 0; - for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_send[0]; k++) //receive row data - { - INMOST_DATA_ENUM_TYPE local_size = 0; - for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_send[j+1]; r++) - local_size += send_row_sizes[q+r]; - GUARD_MPI(MPI_Isend(&send_row_data[f],local_size,Sparse::GetRowEntryType(),vector_exchange_send[j],4*size+rank,comm,&requests[k+vector_exchange_recv[0]])); - q += vector_exchange_send[j+1]; - j += vector_exchange_send[j+1]+2; - f += local_size; - } + INMOST_DATA_ENUM_TYPE Solver::GetPropertyEnum(std::string property) const { + return solver->GetPropertyEnum(property); + } - - local_start = local_end; - m.SetInterval(local_matrix_begin,ext_pos); - local_end = ext_pos; - if( vector_exchange_recv[0]+vector_exchange_send[0] > 0 ) - GUARD_MPI(MPI_Waitall(vector_exchange_recv[0]+vector_exchange_send[0],&requests[0],MPI_STATUSES_IGNORE)); - j = 1; - q = 0; - f = 0; - for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //extend matrix - { - for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_recv[j+1]; r++) - { - m[global_to_local[vector_exchange_recv[j+2+r]]] = Sparse::Row(&recv_row_data[f],&recv_row_data[f]+recv_row_sizes[q+r]); - f += recv_row_sizes[q+r]; - } - q += vector_exchange_recv[j+1]; - j += vector_exchange_recv[j+1]+2; - } - } - //std::cout << it << "/" << overlap << " done" << std::endl; - } - two[0] = local_matrix_begin; - two[1] = local_end; - GUARD_MPI(MPI_Allgather(two,2,INMOST_MPI_DATA_ENUM_TYPE,&global_overlap[0],2,INMOST_MPI_DATA_ENUM_TYPE,comm)); - //std::cout << __FUNCTION__ << " done" << std::endl; -#endif - } + void Solver::SetPropertyReal(std::string property, INMOST_DATA_REAL_TYPE value) { + solver->SetPropertyReal(property, value); + } - void Solver::OrderInfo::RestoreMatrix(Sparse::Matrix & m) - { - //restore matrix size - m.SetInterval(initial_matrix_begin,initial_matrix_end); - //restore indexes - for(Sparse::Matrix::iterator it = m.Begin(); it != m.End(); ++it) - for(Sparse::Row::iterator jt = it->Begin(); jt != it->End(); ++jt) - if( jt->first >= initial_matrix_end ) - jt->first = extended_indexes[jt->first-initial_matrix_end]; - m.isParallel() = false; - have_matrix = false; -#if defined(USE_MPI) - if( comm != INMOST_MPI_COMM_WORLD ) - { - MPI_Comm_free(&comm); - comm = INMOST_MPI_COMM_WORLD; - } -#endif - //std::cout << __FUNCTION__ << std::endl; - } + void Solver::SetPropertyEnum(std::string property, INMOST_DATA_ENUM_TYPE value) { + solver->SetPropertyEnum(property, value); + } - Solver::OrderInfo::~OrderInfo() - { -#if defined(USE_MPI) - if( comm != INMOST_MPI_COMM_WORLD ) - MPI_Comm_free(&comm); -#endif - } - - void Solver::OrderInfo::Clear() - { - global_to_proc.clear(); - global_overlap.clear(); - vector_exchange_recv.clear(); - vector_exchange_send.clear(); - send_storage.clear(); - recv_storage.clear(); - send_requests.clear(); - recv_requests.clear(); - extended_indexes.clear(); - local_vector_begin = local_vector_end = 0; - initial_matrix_begin = initial_matrix_end = 0; - local_matrix_begin = local_matrix_end = 0; - have_matrix = false; - } - - void Solver::OrderInfo::PrepareVector(Sparse::Vector & v) const - { - if( !have_matrix ) throw PrepareMatrixFirst; - v.SetInterval(local_vector_begin,local_vector_end); - v.isParallel() = true; - } - - void Solver::OrderInfo::RestoreVector(Sparse::Vector & v) const - { - assert(have_matrix); - if( v.isParallel() ) - { - v.SetInterval(initial_matrix_begin,initial_matrix_end); - v.isParallel() = false; - } - } - - Solver::OrderInfo::OrderInfo() : - global_to_proc(), - global_overlap(), - vector_exchange_recv(), - vector_exchange_send(), - send_storage(), - recv_storage(), - send_requests(), - recv_requests(), - extended_indexes() - { - comm = INMOST_MPI_COMM_WORLD; - rank = 0; - size = 1; - initial_matrix_begin = 0; - initial_matrix_end = 0; - local_matrix_begin = 0; - local_matrix_end = 0; - local_vector_begin = 0; - local_vector_end = 0; - have_matrix = false; - } - - Solver::OrderInfo::OrderInfo(const OrderInfo & other) - :global_to_proc(other.global_to_proc), global_overlap(other.global_overlap), - vector_exchange_recv(other.vector_exchange_recv), vector_exchange_send(other.vector_exchange_send), - extended_indexes(other.extended_indexes) - { -#if defined(USE_MPI) - if( other.comm == INMOST_MPI_COMM_WORLD ) - comm = INMOST_MPI_COMM_WORLD; - else MPI_Comm_dup(other.comm,&comm); -#else - comm = other.comm; -#endif - rank = other.rank; - size = other.size; - initial_matrix_begin = other.initial_matrix_begin; - initial_matrix_end = other.initial_matrix_end; - local_vector_begin = other.local_vector_begin; - local_vector_end = other.local_vector_end; - local_matrix_begin = other.local_matrix_begin; - local_matrix_end = other.local_matrix_end; - have_matrix = other.have_matrix; - send_storage.resize(other.send_storage.size()); - recv_storage.resize(other.recv_storage.size()); - send_requests.resize(other.send_requests.size()); - recv_requests.resize(other.recv_requests.size()); - } - - Solver::OrderInfo & Solver::OrderInfo::operator =(OrderInfo const & other) - { -#if defined(USE_MPI) - if( other.comm == INMOST_MPI_COMM_WORLD ) - comm = INMOST_MPI_COMM_WORLD; - else MPI_Comm_dup(other.comm,&comm); -#else - comm = other.comm; -#endif - global_to_proc = other.global_to_proc; - global_overlap = other.global_overlap; - vector_exchange_recv = other.vector_exchange_recv; - vector_exchange_send = other.vector_exchange_send; - extended_indexes = other.extended_indexes; - rank = other.rank; - size = other.size; - initial_matrix_begin = other.initial_matrix_begin; - initial_matrix_end = other.initial_matrix_end; - local_vector_begin = other.local_vector_begin; - local_vector_end = other.local_vector_end; - local_matrix_begin = other.local_matrix_begin; - local_matrix_end = other.local_matrix_end; - have_matrix = other.have_matrix; - send_storage.resize(other.send_storage.size()); - recv_storage.resize(other.recv_storage.size()); - send_requests.resize(other.send_requests.size()); - recv_requests.resize(other.recv_requests.size()); - return *this; - } + const INMOST_DATA_ENUM_TYPE Solver::Iterations() const { + return solver->Iterations(); + } + const INMOST_DATA_REAL_TYPE Solver::Residual() const { + return solver->Residual(); + } - INMOST_DATA_ENUM_TYPE Solver::OrderInfo::GetProcessor(INMOST_DATA_ENUM_TYPE gind) const - { - assert(have_matrix); - storage_type::const_iterator find = std::lower_bound(global_to_proc.begin(),global_to_proc.end(),gind); - assert(find != global_to_proc.end()); - if( (*find) == gind && find+1 != global_to_proc.end()) return static_cast(find - global_to_proc.begin()); - else return static_cast(find - global_to_proc.begin())-1; - } - void Solver::OrderInfo::GetOverlapRegion(INMOST_DATA_ENUM_TYPE proc, INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const - { - assert(have_matrix); - mbeg = global_overlap[proc*2+0]; - mend = global_overlap[proc*2+1]; - } - void Solver::OrderInfo::GetLocalRegion(INMOST_DATA_ENUM_TYPE proc, INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const - { - assert(have_matrix); - mbeg = global_to_proc[proc+0]; - mend = global_to_proc[proc+1]; - } - - - void Solver::OrderInfo::Update(Sparse::Vector & x) - { - //std::cout << __FUNCTION__ << " start" << std::endl; -#if defined(USE_MPI) - if( GetSize() == 1 ) return; -#if defined(USE_OMP) -#pragma omp single -#endif - { - //use MPI_Put/MPI_Get to update vector - assert(x.isParallel()); //the vector was prepared - INMOST_DATA_ENUM_TYPE i, j = 1, k, l = 0; - int ierr; - for(i = 0; i < vector_exchange_recv[0]; i++) - { - //std::cout << GetRank() << " MPI_Irecv size " << vector_exchange_recv[j+1] << " dest " << vector_exchange_recv[j] << " tag " << vector_exchange_recv[j]*size+rank << std::endl; - GUARD_MPI(MPI_Irecv(&recv_storage[l],vector_exchange_recv[j+1],INMOST_MPI_DATA_REAL_TYPE,vector_exchange_recv[j],vector_exchange_recv[j]*size+rank,comm,&recv_requests[i])); - l += vector_exchange_recv[j+1]; - j += vector_exchange_recv[j+1] + 2; - } - j = 1, l = 0; - for(i = 0; i < vector_exchange_send[0]; i++) - { - //std::cout << GetRank() << " MPI_Isend size " << vector_exchange_send[j+1] << " dest " << vector_exchange_send[j] << " tag " << rank*size+vector_exchange_send[j] << std::endl; - for(k = 0; k < vector_exchange_send[j+1]; k++) - send_storage[l+k] = x[vector_exchange_send[k+j+2]]; - GUARD_MPI(MPI_Isend(&send_storage[l],vector_exchange_send[j+1],INMOST_MPI_DATA_REAL_TYPE,vector_exchange_send[j],rank*size+vector_exchange_send[j],comm,&send_requests[i])); - l += vector_exchange_send[j+1]; - j += vector_exchange_send[j+1] + 2; - } - if( vector_exchange_recv[0] > 0 ) - { - GUARD_MPI(MPI_Waitall(static_cast(recv_requests.size()),&recv_requests[0],MPI_STATUSES_IGNORE)); - j = 1, l = 0; - for(i = 0; i < vector_exchange_recv[0]; i++) - { - for(k = 0; k < vector_exchange_recv[j+1]; k++) - x[vector_exchange_recv[k+j+2]] = recv_storage[l+k]; - l += vector_exchange_recv[j+1]; - j += vector_exchange_recv[j+1] + 2; - } - } - if( vector_exchange_send[0] > 0 ) - { - GUARD_MPI(MPI_Waitall(static_cast(send_requests.size()),&send_requests[0],MPI_STATUSES_IGNORE)); - } - } -#else - (void) x; -#endif - //std::cout << __FUNCTION__ << " end" << std::endl; - } - void Solver::OrderInfo::Accumulate(Sparse::Vector & x) - { - //std::cout << __FUNCTION__ << " start" << std::endl; -#if defined(USE_MPI) - if( GetSize() == 1 ) return; -#if defined(USE_OMP) -#pragma omp single -#endif - { - //use MPI_Put/MPI_Get to update vector - assert(x.isParallel()); //the vector was prepared - INMOST_DATA_ENUM_TYPE i, j = 1, k, l = 0; - int ierr; - for(i = 0; i < vector_exchange_send[0]; i++) - { - //std::cout << GetRank() << " MPI_Irecv size " << vector_exchange_send[j+1] << " dest " << vector_exchange_send[j] << " tag " << vector_exchange_send[j]*size+rank << std::endl; - GUARD_MPI(MPI_Irecv(&send_storage[l],vector_exchange_send[j+1],INMOST_MPI_DATA_REAL_TYPE,vector_exchange_send[j],vector_exchange_send[j]*size+rank,comm,&send_requests[i])); - l += vector_exchange_send[j+1]; - j += vector_exchange_send[j+1] + 2; - } - j = 1, l = 0; - for(i = 0; i < vector_exchange_recv[0]; i++) - { - for(k = 0; k < vector_exchange_recv[j+1]; k++) - recv_storage[l+k] = x[vector_exchange_recv[k+j+2]]; - //std::cout << GetRank() << " MPI_Isend size " << vector_exchange_recv[j+1] << " dest " << vector_exchange_recv[j] << " tag " << rank*size+vector_exchange_recv[j] << std::endl; - GUARD_MPI(MPI_Isend(&recv_storage[l],vector_exchange_recv[j+1],INMOST_MPI_DATA_REAL_TYPE,vector_exchange_recv[j],rank*size+vector_exchange_recv[j],comm,&recv_requests[i])); - l += vector_exchange_recv[j+1]; - j += vector_exchange_recv[j+1] + 2; - } - if( vector_exchange_send[0] > 0 ) - { - //std::cout << GetRank() << " Waitall send " << send_requests.size() << std::endl; - GUARD_MPI(MPI_Waitall(static_cast(send_requests.size()),&send_requests[0],MPI_STATUSES_IGNORE)); - j = 1, l = 0; - for(i = 0; i < vector_exchange_send[0]; i++) - { - for(k = 0; k < vector_exchange_send[j+1]; k++) - x[vector_exchange_send[k+j+2]] += send_storage[l+k]; - l += vector_exchange_send[j+1]; - j += vector_exchange_send[j+1] + 2; - } - } - if( vector_exchange_recv[0] > 0 ) - { - //std::cout << GetRank() << " Waitall recv " << recv_requests.size() << std::endl; - GUARD_MPI(MPI_Waitall(static_cast(recv_requests.size()),&recv_requests[0],MPI_STATUSES_IGNORE)); - } - } -#else - (void) x; -#endif - //std::cout << __FUNCTION__ << " end" << std::endl; - } - /* - void Solver::OrderInfo::ScalarProd(Vector const & left, Vector const & right, INMOST_DATA_ENUM_TYPE index_begin, INMOST_DATA_ENUM_TYPE index_end, INMOST_DATA_REAL_TYPE & sum) const - { - INMOST_DATA_INTEGER_TYPE ibeg = index_begin, iend = index_end; -#if defined(USE_OMP) -#pragma omp for reduction(+:sum) -#endif - for(INMOST_DATA_INTEGER_TYPE i = ibeg; i < iend; ++i) - { - sum += left[i]*right[i]; - } - Integrate(&sum,1); - } - */ - - - - + const std::string Solver::ReturnReason() const { + return solver->ReturnReason(); + } + Solver::~Solver() { + solver->Finalize(); + delete solver; + } + std::string Solver::parseDatabase(std::string solverName) { + const char *name = solverName.c_str(); + if( database != NULL ) { + FILE * f = fopen(database, "r"); + if (f != NULL) { + char str[4096]; + while( !feof(f) && fgets(str,4096,f)) { + int k = 0, l; + for(k = 0; k < (int)strlen(str); ++k) { + if( str[k] == ':' ) break; + } + if( k == strlen(str) ) continue; //invalid line + for(l = 0; l < k; ++l) str[l] = tolower(str[l]); + l = (int)strlen(str)-1; // Right-trim string + while(l > 0 && isspace(str[l]) ) --l; + str[l+1] = 0; + l = k+1; + while(l < (int)strlen(str) && isspace(str[l]) ) ++l; + if( l == strlen(str) ) continue; //skip empty entry + if( !strncmp(str, name, k) ) { + return std::string(str+l); + } + } + fclose(f); + } + } + return std::string(""); + } - + int comparator(const void * pa, const void *pb) + { + INMOST_DATA_ENUM_TYPE * a = (INMOST_DATA_ENUM_TYPE *)pa, * b = (INMOST_DATA_ENUM_TYPE *)pb; + return a[0] - b[0]; + } - //====================================================================== - //SOLVER SOURCE CODE - //====================================================================== - void Solver::Initialize(int * argc, char *** argv, const char * database) - { - (void)database; - (void)argc; - (void)argv; - if( database != NULL ) - { - FILE * f = fopen(database,"r"); - if( f ) - { - //std::fstream file(database,std::ios::in); - char str[4096]; - //while( !file.eof() && file.getline(str,4096) ) - while( !feof(f) && fgets(str,4096,f) ) - { - int k = 0, l; - for(k = 0; k < (int)strlen(str); ++k) - { - if( str[k] == ':' ) break; - } - if( k == strlen(str) ) continue; //invalid line - for(l = 0; l < k; ++l) str[l] = tolower(str[l]); - l = (int)strlen(str)-1; // Right-trim string - while(l > 0 && isspace(str[l]) ) --l; - str[l+1] = 0; - l = k+1; - while(l < (int)strlen(str) && isspace(str[l]) ) ++l; - if( l == strlen(str) ) continue; //skip empty entry - if( !strncmp(str,"petsc",k) ) - petsc_database_file = std::string(str+l); - else if( !strncmp(str,"trilinos_ifpack",k) ) - trilinos_ifpack_database_file = std::string(str+l); - else if( !strncmp(str,"trilinos_aztec",k) ) - trilinos_aztec_database_file = std::string(str+l); - else if( !strncmp(str,"trilinos_ml",k) ) - trilinos_ml_database_file = std::string(str+l); - else if( !strncmp(str,"trilinos_belos",k) ) - trilinos_belos_database_file = std::string(str+l); - else if( !strncmp(str,"ani",k) ) - ani_database_file = std::string(str+l); - else if( !strncmp(str,"fcbiilu2",k) ) - fcbiilu2_database_file = std::string(str+l); - else if( !strncmp(str,"k3biilu2",k) ) - k3biilu2_database_file = std::string(str+l); - else if( !strncmp(str,"superlu",k) ) - superlu_database_file = std::string(str+l); - } - //file.close(); - fclose(f); - } - } - //std::cout << "PETSc \"" << petsc_database_file << "\"" << std::endl; - //std::cout << "Trilinos_Ifpack \"" << trilinos_ifpack_database_file << "\"" << std::endl; -#if defined(USE_SOLVER_PETSC) - SolverInitializePetsc(argc,argv,petsc_database_file.c_str()); -#endif -#if defined(USE_SOLVER_SUPERLU) - SolverInitializeSuperLU(argc,argv,superlu_database_file.c_str()); -#endif -#if defined(USE_SOLVER_ANI) - SolverInitializeAni(argc,argv,ani_database_file.c_str()); -#endif -#if defined(HAVE_SOLVER_FCBIILU2) - SolverInitializeFcbiilu2(argc,argv,fcbiilu2_database_file.c_str()); -#endif -#if defined(HAVE_SOLVER_K3BIILU2) - SolverInitializeK3biilu2(argc,argv,k3biilu2_database_file.c_str()); -#endif -#if defined(USE_MPI) - { - int flag = 0; - int ierr = 0; - MPI_Initialized(&flag); - if( !flag ) - { - ierr = MPI_Init(argc,argv); - if( ierr != MPI_SUCCESS ) - { - std::cout << __FILE__ << ":" << __LINE__ << "problem in MPI_Init" << std::endl; - } - } - } -#endif -#if defined(USE_SOLVER_SUPERLU) - -#endif - Sparse::CreateRowEntryType(); - is_initialized = true; - } - - void Solver::Finalize() - { - Sparse::DestroyRowEntryType(); -#if defined(USE_SOLVER_PETSC) - SolverFinalizePetsc(); -#endif -#if defined(USE_SOLVER_ANI) - SolverFinalizeAni(); -#endif -#if defined(HAVE_SOLVER_FCBIILU2) - SolverFinalizeFcbiilu2(); -#endif -#if defined(HAVE_SOLVER_K3BIILU2) - SolverFinalizeK3biilu2(); -#endif + INMOST_DATA_ENUM_TYPE binary_search_pairs(INMOST_DATA_ENUM_TYPE * link, INMOST_DATA_ENUM_TYPE size, INMOST_DATA_ENUM_TYPE find) + { + INMOST_DATA_ENUM_TYPE rcur = size >> 1, lcur = 0, mid, chk; + while( rcur >= lcur ) + { + mid = lcur + ((rcur-lcur) >> 1); + chk = mid << 1; + if( link[chk] < find ) lcur = mid+1; + else if( link[chk] > find ) rcur = mid-1; + else return chk; + } + return size; + } + void Solver::OrderInfo::Integrate(INMOST_DATA_REAL_TYPE * inout, INMOST_DATA_ENUM_TYPE num) const + { #if defined(USE_MPI) - { - int flag = 0; - MPI_Finalized(&flag); - if( !flag ) - MPI_Finalize(); - } -#endif - is_initialized = false; - is_finalized = true; - } - void Solver::SetParameterEnum(std::string name, INMOST_DATA_ENUM_TYPE val) - { - if( name == "maximum_iterations" ) - maximum_iterations = val; - else if( name == "rescale_iterations" ) - preconditioner_rescale_iterations = val; - else if( name == "condition_estimation" ) - preconditioner_condition_estimation = val; - else if( name == "adapt_ddpq_tolerance" ) - preconditioner_adapt_ddpq_tolerance = val; - else if( name == "schwartz_overlap" ) - additive_schwartz_overlap = val; - else if( name == "gmres_substeps" ) - solver_gmres_substeps = val; - else if( name == "reorder_nonzeros" ) - preconditioner_reorder_nonzero = val; - /* Block below leads to confusion - parameters would be reset by preset values during setup - else if( _pack == INNER_ILU2 || _pack == INNER_MLILUC ) - { - try - { - //This leads to confusion - - IterativeMethod * method = (IterativeMethod *)solver_data; - if (name[0] == ':') - method->EnumParameter(name.substr(1, name.size() - 1)) = val; - else if (name == "overlap") additive_schwartz_overlap = val; - else method->EnumParameter(name) = val; - } - catch(...) - { - std::cout << "Parameter " << name << " of intergral type is unknown" << std::endl; - } - } - */ - else std::cout << "Parameter " << name << " of integral type is unknown" << std::endl; - } - void Solver::SetParameterReal(std::string name, INMOST_DATA_REAL_TYPE val) - { - if( name == "absolute_tolerance" ) - absolute_tolerance = val; - else if( name == "relative_tolerance" ) - relative_tolerance = val; - else if( name == "divergence_tolerance" ) - divergence_tolerance = val; - else if( name == "drop_tolerance" ) - preconditioner_drop_tolerance = val; - else if( name == "reuse_tolerance" ) - preconditioner_reuse_tolerance = val; - else if( name == "ddpq_tolerance" ) - preconditioner_ddpq_tolerance = val; - else if( name == "fill_level" ) - preconditioner_fill_level = val; - /* Block below leads to confusion - parameters would be reset by preset values during setup - else if( _pack == INNER_ILU2 || _pack == INNER_MLILUC ) - { - try - { - IterativeMethod * method = (IterativeMethod *)solver_data; - if (name[0] == ':') method->RealParameter(name.substr(1, name.size() - 1)) = val; - else method->RealParameter(name) = val; - } - catch(...) - { - std::cout << "Parameter " << name << " of real type is unknown" << std::endl; - } - } - */ - else std::cout << "Parameter " << name << " of real type is unknown" << std::endl; - } - Solver::Solver(Type pack, std::string _name, INMOST_MPI_Comm _comm) - { - additive_schwartz_overlap = DEFAULT_ADDITIVE_SCHWARTZ_OVERLAP; - maximum_iterations = DEFAULT_MAXIMUM_ITERATIONS; - absolute_tolerance = DEFAULT_ABSOLUTE_TOLERANCE; - relative_tolerance = DEFAULT_RELATIVE_TOLERANCE; - divergence_tolerance = DEFAULT_DIVERGENCE_TOLERANCE; - preconditioner_ddpq_tolerance = DEFAULT_PRECONDITIONER_DDPQ_TOLERANCE; - preconditioner_drop_tolerance = DEFAULT_PRECONDITIONER_DROP_TOLERANCE; - preconditioner_reuse_tolerance = DEFAULT_PRECONDITIONER_REUSE_TOLERANCE; - preconditioner_reorder_nonzero = DEFAULT_PRECONDITIONER_REORDER_NONZEROS; - preconditioner_rescale_iterations = DEFAULT_PRECONDITIONER_RESCALE_ITERS; - preconditioner_fill_level = DEFAULT_PRECONDITIONER_FILL_LEVEL; - preconditioner_adapt_ddpq_tolerance = DEFAULT_PRECONDITIONER_ADAPT_DDPQ_TOLERANCE; - preconditioner_condition_estimation = DEFAULT_PRECONDITIONER_CONDITION_ESTIMATION; - solver_gmres_substeps = DEFAULT_SOLVER_GMRES_SUBSTEPS; - comm = _comm; - _pack = pack; - name = _name; - solver_data = NULL; - local_size = global_size = 0; - last_it = 0; - last_resid = 0; - matrix_data = rhs_data = solution_data = precond_data = NULL; -#if defined(USE_SOLVER_PETSC) - if( _pack == PETSc ) - { - SolverInitDataPetsc(&solver_data,_comm,name.c_str()); - } -#endif -#if defined(USE_SOLVER_ANI) - if( _pack == ANI ) - { - SolverInitDataAni(&solver_data,_comm,name.c_str()); - } -#endif -#if defined(HAVE_SOLVER_FCBIILU2) - if( _pack == FCBIILU2 ) - { - SolverInitDataFcbiilu2(&solver_data,_comm,name.c_str()); - } -#endif -#if defined(HAVE_SOLVER_K3BIILU2) - if( _pack == K3BIILU2 ) - { - SolverInitDataK3biilu2(&solver_data,_comm,name.c_str()); - } -#endif -#if defined(USE_SOLVER_SUPERLU) - if( _pack == SUPERLU ) - { - SolverInitDataSuperLU(&solver_data); - } -#endif -#if defined(USE_SOLVER_TRILINOS) - if( _pack == Trilinos_Aztec || - _pack == Trilinos_Belos || - _pack == Trilinos_ML || - _pack == Trilinos_Ifpack) - { - std::pair * problem = - new std::pair; - problem->first = _name; - solver_data = static_cast(problem); - } -#endif - if( _pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILUC || _pack == INNER_MPTILU2) - { - Method * prec; - if (_pack == INNER_ILU2) - { -#if defined(__SOLVER_ILU2__) - prec = new ILU2_preconditioner(info); -#else - std::cout << "Sorry, ILU2 preconditioner is not included in this release" << std::endl; - prec = NULL; -#endif - } - else if( _pack == INNER_DDPQILUC ) - { -#if defined(__SOLVER_DDPQILUC2__) - prec = new ILUC_preconditioner(info); -#else - std::cout << "Sorry, multilevel condition estimation crout-ilu preconditioner with reordering for diagonal dominance is not included in this release" << std::endl; - prec = NULL; -#endif - } - else if( _pack == INNER_MPTILUC ) - { -#if defined(__SOLVER_MTILUC2__) - prec = new MTILUC_preconditioner(info); -#else - std::cout << "Sorry, maximum product transverse condition estimation crout-ilu preconditioner is not included in this release" << std::endl; - prec = NULL; + if( GetSize() == 1 ) return; +#if defined(USE_OMP) +#pragma omp single #endif - } - else if( _pack == INNER_MPTILU2 ) - { -#if defined(__SOLVER_MTILU2__) - prec = new MTILU2_preconditioner(info); + { + int ierr = 0; + dynarray temp(num); + memcpy(temp.data(),inout,sizeof(INMOST_DATA_REAL_TYPE)*num); + GUARD_MPI(MPI_Allreduce(temp.data(),inout,num,INMOST_MPI_DATA_REAL_TYPE,MPI_SUM,comm)); + } #else - std::cout << "Sorry, maximum product transverse ilu2 preconditioner is not included in this release" << std::endl; - prec = NULL; -#endif - } - else prec = NULL; - solver_data = new KSOLVER(prec, info); - } - } - Solver::Solver(const Solver & other) - { - comm = other.comm; -#if defined(USE_SOLVER_PETSC) - if( _pack == PETSc ) - { - SolverCopyDataPetsc(&solver_data,other.solver_data,comm); - if( other.matrix_data != NULL ) - { - MatrixCopyDataPetsc(&matrix_data,other.matrix_data); - SolverSetMatrixPetsc(solver_data,matrix_data,false,false); - } - if( other.rhs_data != NULL ) - VectorCopyDataPetsc(&rhs_data,other.rhs_data); - if( other.solution_data != NULL ) - VectorCopyDataPetsc(&solution_data,other.solution_data); - } -#endif -#if defined(USE_SOLVER_ANI) - if( _pack == ANI ) - { - SolverCopyDataAni(&solver_data,other.solver_data,comm); - if( other.matrix_data != NULL ) - { - MatrixCopyDataAni(&matrix_data,other.matrix_data); - SolverSetMatrixAni(solver_data,matrix_data,false,false); - } - if( other.rhs_data != NULL ) - VectorCopyDataAni(&rhs_data,other.rhs_data); - if( other.solution_data != NULL ) - VectorCopyDataAni(&solution_data,other.solution_data); - } + (void) inout; + (void) num; #endif -#if defined(HAVE_SOLVER_FCBIILU2) - if( _pack == FCBIILU2 ) - { - SolverCopyDataFcbiilu2(&solver_data,other.solver_data,comm); - if( other.matrix_data != NULL ) - { - MatrixCopyDataFcbiilu2(&matrix_data,other.matrix_data); - SolverSetMatrixFcbiilu2(solver_data,matrix_data,false,false); - } - if( other.rhs_data != NULL ) - VectorCopyDataFcbiilu2(&rhs_data,other.rhs_data); - if( other.solution_data != NULL ) - VectorCopyDataFcbiilu2(&solution_data,other.solution_data); - } -#endif -#if defined(HAVE_SOLVER_K3BIILU2) - if( _pack == K3BIILU2 ) - { - SolverCopyDataK3biilu2(&solver_data,other.solver_data,comm); - if( other.matrix_data != NULL ) - { - MatrixCopyDataK3biilu2(&matrix_data,other.matrix_data); - SolverSetMatrixK3biilu2(solver_data,matrix_data,false,false); - } - if( other.rhs_data != NULL ) - VectorCopyDataK3biilu2(&rhs_data,other.rhs_data); - if( other.solution_data != NULL ) - VectorCopyDataK3biilu2(&solution_data,other.solution_data); - } -#endif -#if defined(USE_SOLVER_TRILINOS) - if( _pack == Trilinos_Aztec || - _pack == Trilinos_Belos || - _pack == Trilinos_ML || - _pack == Trilinos_Ifpack) - { - throw - 1; //You should not really want to copy solver's information - } -#endif - if (_pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILUC || _pack == INNER_MPTILU2) - { - throw - 1; //You should not really want to copy solver's information - } - } - void Solver::Clear() - { - local_size = global_size = 0; - info.Clear(); -#if defined(USE_SOLVER_PETSC) - if( _pack == PETSc ) - { - if( matrix_data != NULL ) - MatrixDestroyDataPetsc(&matrix_data); - if( rhs_data != NULL ) - VectorDestroyDataPetsc(&rhs_data); - if( solution_data != NULL ) - VectorDestroyDataPetsc(&solution_data); - SolverDestroyDataPetsc(&solver_data); - } -#endif -#if defined(USE_SOLVER_ANI) - if( _pack == ANI ) - { - if( matrix_data != NULL ) - MatrixDestroyDataAni(&matrix_data); - if( rhs_data != NULL ) - VectorDestroyDataAni(&rhs_data); - if( solution_data != NULL ) - VectorDestroyDataAni(&solution_data); - SolverDestroyDataAni(&solver_data); - } -#endif -#if defined(HAVE_SOLVER_FCBIILU2) - if( _pack == FCBIILU2 ) - { - if( matrix_data != NULL ) - MatrixDestroyDataFcbiilu2(&matrix_data); - if( rhs_data != NULL ) - VectorDestroyDataFcbiilu2(&rhs_data); - if( solution_data != NULL ) - VectorDestroyDataFcbiilu2(&solution_data); - SolverDestroyDataFcbiilu2(&solver_data); - } -#endif -#if defined(HAVE_SOLVER_K3BIILU2) - if( _pack == K3BIILU2 ) - { - if( matrix_data != NULL ) - MatrixDestroyDataK3biilu2(&matrix_data); - if( rhs_data != NULL ) - VectorDestroyDataK3biilu2(&rhs_data); - if( solution_data != NULL ) - VectorDestroyDataK3biilu2(&solution_data); - SolverDestroyDataK3biilu2(&solver_data); - } -#endif -#if defined(USE_SOLVER_TRILINOS) - if( _pack == Trilinos_Aztec || - _pack == Trilinos_Belos || - _pack == Trilinos_ML || - _pack == Trilinos_Ifpack) - { - if( matrix_data != NULL ) - { - delete static_cast(matrix_data); - matrix_data = NULL; - } - if( solver_data != NULL ) - { - delete static_cast *>(solver_data); - solver_data = NULL; - } - } -#endif -#if defined(USE_SOLVER_SUPERLU) - if(_pack == SUPERLU ) - { - SolverDestroyDataSuperLU(&solver_data); - matrix_data = NULL; - } -#endif - if (_pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILUC || _pack == INNER_MPTILU2) - { - if( matrix_data != NULL ) - { - delete (Sparse::Matrix * )matrix_data; - matrix_data = NULL; - } - if( solver_data != NULL ) - { - delete (Method *)solver_data; - solver_data = NULL; - } - } - } - Solver::~Solver() - { - Clear(); - } - Solver & Solver::operator =(Solver const & other) - { - if( this != &other ) - { - comm = other.comm; -#if defined(USE_SOLVER_PETSC) - if( _pack == PETSc ) - { - SolverAssignDataPetsc(solver_data,other.solver_data); - if( other.matrix_data != NULL ) - { - if( matrix_data != NULL ) - MatrixAssignDataPetsc(matrix_data,other.matrix_data); - else - MatrixCopyDataPetsc(&matrix_data,other.matrix_data); - SolverSetMatrixPetsc(solver_data,matrix_data,false,false); - } - if( other.rhs_data != NULL ) - { - if( rhs_data != NULL ) - VectorAssignDataPetsc(rhs_data,other.rhs_data); - else - VectorCopyDataPetsc(&rhs_data,other.rhs_data); - } - if( other.solution_data != NULL ) - { - if( solution_data != NULL ) - VectorAssignDataPetsc(solution_data,other.solution_data); - else - VectorCopyDataPetsc(&solution_data,other.solution_data); - } - } -#endif -#if defined(USE_SOLVER_ANI) - if( _pack == ANI ) - { - SolverAssignDataAni(solver_data,other.solver_data); - if( other.matrix_data != NULL ) - { - if( matrix_data != NULL ) - MatrixAssignDataAni(matrix_data,other.matrix_data); - else - MatrixCopyDataAni(&matrix_data,other.matrix_data); - SolverSetMatrixAni(solver_data,matrix_data,false,false); - } - if( other.rhs_data != NULL ) - { - if( rhs_data != NULL ) - VectorAssignDataAni(rhs_data,other.rhs_data); - else - VectorCopyDataAni(&rhs_data,other.rhs_data); - } - if( other.solution_data != NULL ) - { - if( solution_data != NULL ) - VectorAssignDataAni(solution_data,other.solution_data); - else - VectorCopyDataAni(&solution_data,other.solution_data); - } - } -#endif -#if defined(HAVE_SOLVER_FCBIILU2) - if( _pack == FCBIILU2 ) - { - SolverAssignDataFcbiilu2(solver_data,other.solver_data); - if( other.matrix_data != NULL ) - { - if( matrix_data != NULL ) - MatrixAssignDataFcbiilu2(matrix_data,other.matrix_data); - else - MatrixCopyDataFcbiilu2(&matrix_data,other.matrix_data); - SolverSetMatrixFcbiilu2(solver_data,matrix_data,false,false); - } - if( other.rhs_data != NULL ) - { - if( rhs_data != NULL ) - VectorAssignDataFcbiilu2(rhs_data,other.rhs_data); - else - VectorCopyDataFcbiilu2(&rhs_data,other.rhs_data); - } - if( other.solution_data != NULL ) - { - if( solution_data != NULL ) - VectorAssignDataFcbiilu2(solution_data,other.solution_data); - else - VectorCopyDataFcbiilu2(&solution_data,other.solution_data); - } - } -#endif -#if defined(HAVE_SOLVER_K3BIILU2) - if( _pack == K3BIILU2 ) - { - SolverAssignDataK3biilu2(solver_data,other.solver_data); - if( other.matrix_data != NULL ) - { - if( matrix_data != NULL ) - MatrixAssignDataK3biilu2(matrix_data,other.matrix_data); - else - MatrixCopyDataK3biilu2(&matrix_data,other.matrix_data); - SolverSetMatrixK3biilu2(solver_data,matrix_data,false,false); - } - if( other.rhs_data != NULL ) - { - if( rhs_data != NULL ) - VectorAssignDataK3biilu2(rhs_data,other.rhs_data); - else - VectorCopyDataK3biilu2(&rhs_data,other.rhs_data); - } - if( other.solution_data != NULL ) - { - if( solution_data != NULL ) - VectorAssignDataK3biilu2(solution_data,other.solution_data); - else - VectorCopyDataK3biilu2(&solution_data,other.solution_data); - } - } -#endif -#if defined(USE_SOLVER_TRILINOS) - if( _pack == Trilinos_Aztec || - _pack == Trilinos_Belos || - _pack == Trilinos_ML || - _pack == Trilinos_Ifpack) - { - throw - 1; //You should not really want to copy solver's information - } -#endif - if (_pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILUC || _pack == INNER_MPTILU2) - { - throw - 1; //You should not really want to copy solver's information - } - } - return *this; - } - - void Solver::SetMatrix(Sparse::Matrix & A, bool ModifiedPattern, bool OldPreconditioner) - { - (void) OldPreconditioner; - bool ok = false; -#if defined(USE_SOLVER_PETSC) - if( _pack == PETSc ) - { - bool modified_pattern = ModifiedPattern; - //~ if( A.comm != comm ) throw DifferentCommunicatorInSolver; - if( matrix_data == NULL ) - { - MatrixInitDataPetsc(&matrix_data,A.GetCommunicator(),A.GetName().c_str()); - modified_pattern = true; - //printf("matrix %p\n",matrix_data); - } - INMOST_DATA_ENUM_TYPE mbeg,mend; - A.GetInterval(mbeg,mend); - if( modified_pattern ) - { - local_size = A.Size(); + } + + + void Solver::OrderInfo::PrepareMatrix(Sparse::Matrix & m, INMOST_DATA_ENUM_TYPE overlap) + { + have_matrix = true; + m.isParallel() = true; + INMOST_DATA_ENUM_TYPE two[2]; + INMOST_DATA_ENUM_TYPE mbeg,mend; + int initial_rank; #if defined(USE_MPI) - MPI_Allreduce(&local_size,&global_size,1,INMOST_MPI_DATA_ENUM_TYPE,MPI_SUM,comm); + int ierr = 0; + if( comm != INMOST_MPI_COMM_WORLD ) + { + MPI_Comm_free(&comm); + comm = INMOST_MPI_COMM_WORLD; + } + if( m.GetCommunicator() == INMOST_MPI_COMM_WORLD ) + comm = INMOST_MPI_COMM_WORLD; + else MPI_Comm_dup(m.GetCommunicator(), &comm); + MPI_Comm_rank(comm,&rank); + MPI_Comm_size(comm,&size); #else - global_size = local_size; -#endif - int max = 0; - { - int * diag_nonzeroes = new int[local_size]; - int * off_diag_nonzeroes = new int[local_size]; - unsigned k = 0; - - for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); ++it) - { - diag_nonzeroes[k] = off_diag_nonzeroes[k] = 0; - for(INMOST_DATA_ENUM_TYPE i = 0; i < it->Size(); i++) - { - INMOST_DATA_ENUM_TYPE index = it->GetIndex(i); - if( index < mbeg || index > mend-1 ) off_diag_nonzeroes[k]++; - else diag_nonzeroes[k]++; - } - if( diag_nonzeroes[k] + off_diag_nonzeroes[k] > max ) max = diag_nonzeroes[k] + off_diag_nonzeroes[k]; - k++; - } - MatrixPreallocatePetsc(matrix_data,local_size,global_size,diag_nonzeroes,off_diag_nonzeroes); - delete [] diag_nonzeroes; - delete [] off_diag_nonzeroes; - } - if( max > 0 ) - { - int * col_positions = new int[max]; - double * col_values = new double[max]; - unsigned k = 0, m; - for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); ++it) - { - m = 0; - for(INMOST_DATA_ENUM_TYPE i = 0; i < it->Size(); i++) - { - col_positions[m] = it->GetIndex(i); - col_values[m] = it->GetValue(i); - m++; - } - MatrixFillPetsc(matrix_data,mbeg+k,m,col_positions,col_values); - k++; - } - delete [] col_positions; - delete [] col_values; - } - } - else - { - unsigned max = 0; - for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); ++it) - if( it->Size() > max ) max = it->Size(); - int * col_positions = new int[max]; - double * col_values = new double[max]; - unsigned k = 0, m; - for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); ++it) - { - m = 0; - for(INMOST_DATA_ENUM_TYPE i = 0; i < it->Size(); i++) - { - col_positions[m] = it->GetIndex(i); - col_values[m] = it->GetValue(i); - m++; - } - MatrixFillPetsc(matrix_data,mbeg+k,m,col_positions,col_values); - k++; - } - delete [] col_positions; - delete [] col_values; - } - MatrixFinalizePetsc(matrix_data); - if( petsc_database_file == "" ) //set parameters if no file is set - { - SolverSetDropTolerancePetsc(solver_data,preconditioner_drop_tolerance); - SolverSetFillLevelPetsc(solver_data,preconditioner_fill_level); - SolverSetOverlapPetsc(solver_data,additive_schwartz_overlap); - } - SolverSetMatrixPetsc(solver_data,matrix_data,modified_pattern,OldPreconditioner); - ok = true; - } -#endif -#if defined(USE_SOLVER_ANI) - if( _pack == ANI ) - { - bool modified_pattern = ModifiedPattern; - if( matrix_data == NULL ) - { - MatrixInitDataAni(&matrix_data,A.GetCommunicator(),A.GetName().c_str()); - modified_pattern = true; - } - if( modified_pattern ) - { - global_size = local_size = A.Size(); - - MatrixDestroyDataAni(&matrix_data); - MatrixInitDataAni(&matrix_data,A.GetCommunicator(),A.GetName().c_str()); - INMOST_DATA_ENUM_TYPE nnz = 0, k = 0, q = 1, shift = 1; - int n = A.Size(); - int * ia = (int *)malloc(sizeof(int)*(n+1)); - for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) nnz += it->Size(); - int * ja = (int *)malloc(sizeof(int)*nnz); - double * values = (double *) malloc(sizeof(double)*nnz); - ia[0] = shift; - for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) - { - for(Sparse::Row::iterator jt = it->Begin(); jt != it->End(); jt++) - { - ja[k] = jt->first + 1; - values[k] = jt->second; - k++; - } - shift += it->Size(); - ia[q++] = shift; - } - MatrixFillAni(matrix_data,n,ia,ja,values); - } - else - { - INMOST_DATA_ENUM_TYPE nnz = 0, k = 0; - for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) nnz += it->Size(); - double * values = (double *)malloc(sizeof(double)*nnz); - k = 0; - for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) - for(Sparse::Row::iterator jt = it->Begin(); jt != it->End(); jt++) - values[k++] = jt->second; - MatrixFillValuesAni(matrix_data,values); - } - MatrixFinalizeAni(matrix_data); - SolverSetMatrixAni(solver_data,matrix_data,modified_pattern,OldPreconditioner); - ok = true; - } -#endif -#if defined(HAVE_SOLVER_FCBIILU2) - if( _pack == FCBIILU2 ) - { - bool modified_pattern = ModifiedPattern; - //~ if( A.comm != comm ) throw DifferentCommunicatorInSolver; - if( matrix_data == NULL ) - { - MatrixInitDataFcbiilu2(&matrix_data,A.GetCommunicator(),A.GetName().c_str()); - modified_pattern = true; - } - if( modified_pattern ) - { - global_size = local_size = A.Size(); - - MatrixDestroyDataFcbiilu2(&matrix_data); - MatrixInitDataFcbiilu2(&matrix_data,A.GetCommunicator(),A.GetName().c_str()); - INMOST_DATA_ENUM_TYPE nnz = 0, k = 0, q = 1, shift = 1; - int nproc, myid; + (void) overlap; + rank = 0; + size = 1; +#endif + initial_rank = rank; + //std::vector requests; + global_overlap.resize(size*2); + global_to_proc.resize(size+1); + m.GetInterval(mbeg,mend); + global_to_proc[0] = 0; + initial_matrix_begin = mbeg; + initial_matrix_end = mend; + two[0] = mbeg; + two[1] = mend; #if defined(USE_MPI) - MPI_Comm_size(A.GetCommunicator(),&nproc); - MPI_Comm_rank(A.GetCommunicator(),&myid); + GUARD_MPI(MPI_Allgather(two,2,INMOST_MPI_DATA_ENUM_TYPE,&global_overlap[0],2,INMOST_MPI_DATA_ENUM_TYPE,comm)); #else - nproc = 1; - myid = 0; + local_vector_begin = initial_matrix_begin = local_matrix_begin = global_overlap[0] = mbeg; + local_vector_end = initial_matrix_end = local_matrix_end = global_overlap[1] = mend; + global_to_proc[1] = mend; #endif - int * ibl = (int *)malloc(sizeof(int)*(nproc+1)); - ibl[0] = 0; - int n = A.Size(); #if defined(USE_MPI) - INMOST_DATA_ENUM_TYPE mbeg,mend; - A.GetInterval(mbeg,mend); - n = mend - mbeg; - int block_end = mend; - MPI_Allgather(&block_end,1,MPI_INT,&ibl[1],1,MPI_INT,A.GetCommunicator()); -#else - ibl[1] = n; -#endif - int * ia = (int *)malloc(sizeof(int)*(n+1)); - for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) nnz += it->Size(); - int * ja = (int *)malloc(sizeof(int)*nnz); - double * values = (double *) malloc(sizeof(double)*nnz); - ia[0] = shift; - for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) - { - for(Sparse::Row::iterator jt = it->Begin(); jt != it->End(); jt++) - { - ja[k] = jt->first + 1; - values[k] = jt->second; - //std::cout<<"# q="< global_overlap[2*(k+1)] ) + { + //move bounds to equalize sizes + if( global_overlap[2*k+1] - global_overlap[2*k] < global_overlap[2*(k+1)+1] - global_overlap[2*(k+1)] ) + global_overlap[2*k+1]--; //move right bound of the current processor to left + else + global_overlap[2*(k+1)]++; //move left bound of the next processor to right + } + + //TODO: if we need to merge overlapping parts of the matrices - do it here + } + local_matrix_begin = global_overlap[2*rank+0]; + local_matrix_end = global_overlap[2*rank+1]; + for(int k = 0; k < size; k++) + global_to_proc[k+1] = global_overlap[2*k+1]; + } + MPI_Status stat; + INMOST_DATA_ENUM_TYPE ext_pos = local_matrix_end; + //may replace std::map here + small_hash global_to_local; + std::vector< std::pair > current_global_to_local; + std::vector< Sparse::Row::entry > send_row_data, recv_row_data; + std::vector< INMOST_DATA_ENUM_TYPE > send_row_sizes, recv_row_sizes; + std::vector incoming(4*size); + std::vector requests; + INMOST_DATA_ENUM_TYPE total_send = 0, total_recv = 0; + INMOST_DATA_ENUM_TYPE local_start = local_matrix_begin, local_end = local_matrix_end; + for(INMOST_DATA_ENUM_TYPE it = 0; it < overlap+1; it++) + { + total_send = 0, total_recv = 0; + current_global_to_local.clear(); + for(INMOST_DATA_ENUM_TYPE k = local_start; k < local_end; ++k) + { + Sparse::Row & r = m[k]; + INMOST_DATA_ENUM_TYPE jend = r.Size(), ind; + for(INMOST_DATA_ENUM_TYPE j = 0; j < jend; ++j) + { + ind = r.GetIndex(j); + if( ind < local_matrix_begin || ind >= local_matrix_end) + { + INMOST_DATA_ENUM_TYPE & recv_pos = global_to_local[ind]; + if( recv_pos == 0 ) //this number was not assigned yet + { + recv_pos = ext_pos++; + if( it < overlap ) current_global_to_local.push_back(std::make_pair(ind,recv_pos)); + } + } + } + } + if( it == overlap ) + current_global_to_local = global_to_local.serialize(); + std::sort(current_global_to_local.begin(),current_global_to_local.end()); + //if( !current_global_to_local.empty() ) + { + //check all the indexes that comes from other processors + //for every processor we need arrays: + // processor -> (array of index positions where to receive)) + // processor -> (array of index positions from where to send) + memset(&incoming[0],0,sizeof(INMOST_DATA_ENUM_TYPE)*size*2); + vector_exchange_recv.clear(); + vector_exchange_recv.push_back(0); + if( !current_global_to_local.empty() ) + { + INMOST_DATA_ENUM_TYPE proc_beg = GetProcessor(current_global_to_local.begin()->first), proc_end = GetProcessor(current_global_to_local.rbegin()->first)+1; + INMOST_DATA_ENUM_TYPE current_ind = 0; + for(INMOST_DATA_ENUM_TYPE proc = proc_beg; proc < proc_end; proc++) + { + bool first = true; + INMOST_DATA_ENUM_TYPE numind = static_cast(vector_exchange_recv.size() + 1); + while( current_ind < current_global_to_local.size() && current_global_to_local[current_ind].first < global_to_proc[proc+1] ) + { + INMOST_DATA_ENUM_TYPE k = current_global_to_local[current_ind].first; + if( first ) + { + vector_exchange_recv.push_back(proc); + vector_exchange_recv.push_back(1); + vector_exchange_recv.push_back(k); + first = false; + } + else + { + vector_exchange_recv[numind]++; + vector_exchange_recv.push_back(k); + } + current_ind++; + } + if( !first ) + { + incoming[proc]++; + incoming[proc+size] += vector_exchange_recv[numind]; + vector_exchange_recv[0]++; + } + } + } + + GUARD_MPI(MPI_Allreduce(&incoming[0],&incoming[2*size],size*2,INMOST_MPI_DATA_ENUM_TYPE,MPI_SUM,comm)); + //std::cout << GetRank() << " MPI_Allreduce " << __FILE__ << ":" << __LINE__ << " incoming " << incoming[size*2+rank] << " size " << incoming[size*3+rank] << std::endl; + //prepare array that helps exchanging vector values + requests.resize(2*vector_exchange_recv[0] + incoming[size*2+rank]); + INMOST_DATA_ENUM_TYPE j = 1; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //send rows that i want to receive + { + total_recv += vector_exchange_recv[j+1]; + GUARD_MPI(MPI_Isend(&vector_exchange_recv[j+1],1,INMOST_MPI_DATA_ENUM_TYPE,vector_exchange_recv[j],size+vector_exchange_recv[j],comm,&requests[k])); //send number of rows + GUARD_MPI(MPI_Isend(&vector_exchange_recv[j+2],vector_exchange_recv[j+1],INMOST_MPI_DATA_ENUM_TYPE,vector_exchange_recv[j],2*size+vector_exchange_recv[j],comm,&requests[k+vector_exchange_recv[0]])); //send row positions + j += vector_exchange_recv[j+1] + 2; + } + + recv_row_sizes.resize(incoming[size*3+rank]); + vector_exchange_send.resize(1+incoming[size*2+rank]*2+incoming[size*3+rank]); + vector_exchange_send[0] = 0; + j = 1; + for(INMOST_DATA_ENUM_TYPE k = 0; k < incoming[size*2+rank]; k++) //receive rows that others want from me + { + INMOST_DATA_ENUM_TYPE msgsize; + GUARD_MPI(MPI_Recv(&msgsize,1,INMOST_MPI_DATA_ENUM_TYPE,MPI_ANY_SOURCE,size+rank,comm,&stat)); //recv number of rows + vector_exchange_send[j++] = stat.MPI_SOURCE; + vector_exchange_send[j++] = msgsize; + //std::cout << GetRank() << " MPI_Irecv size " << msgsize << " rank " << stat.MPI_SOURCE << " tag " << 2*size+rank << __FILE__ << ":" << __LINE__ << std::endl; + GUARD_MPI(MPI_Irecv(&vector_exchange_send[j],msgsize,INMOST_MPI_DATA_ENUM_TYPE,stat.MPI_SOURCE,2*size+rank,comm,&requests[2*vector_exchange_recv[0]+k])); //recv rows + j += msgsize; + total_send += msgsize; + vector_exchange_send[0]++; + } + assert(total_send == incoming[size*3+rank]); + assert(vector_exchange_send[0] == incoming[size*2+rank]); + if( 2*vector_exchange_recv[0] + incoming[size*2+rank] > 0 ) + GUARD_MPI(MPI_Waitall(2*vector_exchange_recv[0] + incoming[size*2+rank],&requests[0],MPI_STATUSES_IGNORE)); + } + /* + else + { + vector_exchange_recv.resize(1,0); + vector_exchange_send.resize(1,0); + } + */ + if( it == overlap ) + { + //std::cout << rank << " reorder " << std::endl; + //now we need to reorder off-diagonal parts of the matrix + for(INMOST_DATA_ENUM_TYPE k = local_matrix_begin; k < local_end; ++k) + for(Sparse::Row::iterator jt = m[k].Begin(); jt != m[k].End(); ++jt) + if( global_to_local.is_present(jt->first) ) + jt->first = global_to_local[jt->first]; + else + { + assert(jt->first >= local_matrix_begin); + assert(jt->first < local_matrix_end); + } + local_vector_begin = local_matrix_begin; + local_vector_end = ext_pos; + { + // change indexes for recv array + INMOST_DATA_ENUM_TYPE i,j = 1,k; + //for(k = 0; k < GetRank(); k++) MPI_Barrier(comm); + //std::cout << "rank " << GetRank() << std::endl; + //std::cout << "recv:" << std::endl; + for(i = 0; i < vector_exchange_recv[0]; i++) + { + //std::cout << "proc " << vector_exchange_recv[j] << " size " << vector_exchange_recv[j+1] << std::endl; + j++; //skip processor number + for(k = 0; k < vector_exchange_recv[j]; ++k) + { + assert(global_to_local.is_present(vector_exchange_recv[j+k+1])); + vector_exchange_recv[j+k+1] = global_to_local[vector_exchange_recv[j+k+1]]; + assert(vector_exchange_recv[j+k+1] >= local_matrix_end); + } + j+=vector_exchange_recv[j]+1; //add vector length + size position + } + //check that indexes in send array are in local matrix bounds + //std::cout << "send:" << std::endl; +#ifndef NDEBUG + j = 1; + for(i = 0; i < vector_exchange_send[0]; i++) + { + //std::cout << "proc " << vector_exchange_send[j] << " size " << vector_exchange_send[j+1] << std::endl; + j++; //skip processor number + for(k = 0; k < vector_exchange_send[j]; ++k) + { + assert(vector_exchange_send[j+k+1] >= local_matrix_begin); + assert(vector_exchange_send[j+k+1] < local_matrix_end); + } + j+=vector_exchange_send[j]+1; //add vector length + size position + } +#endif + //for(k = GetRank(); k < GetSize(); k++) MPI_Barrier(comm); + } + //prepare array local->global + extended_indexes.resize(local_vector_end-local_matrix_end); + for(std::vector< std::pair >::iterator jt = current_global_to_local.begin(); jt != current_global_to_local.end(); ++jt) + extended_indexes[jt->second-local_matrix_end] = jt->first; + + send_storage.resize(total_send); + recv_storage.resize(total_recv); + send_requests.resize(vector_exchange_send[0]); + recv_requests.resize(vector_exchange_recv[0]); + + } + else + { + send_row_sizes.resize(total_send); + recv_row_sizes.resize(total_recv); + + INMOST_DATA_ENUM_TYPE j = 1, q = 0, f = 0, total_rows_send = 0, total_rows_recv = 0; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //recv sizes of rows + { + GUARD_MPI(MPI_Irecv(&recv_row_sizes[q],vector_exchange_recv[j+1],INMOST_MPI_DATA_ENUM_TYPE,vector_exchange_recv[j],3*size+vector_exchange_recv[j],comm,&requests[k])); + q += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1]+2; + } + j = 1; + q = 0; + + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_send[0]; k++) //send sizes of rows + { + for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_send[j+1]; r++) + { + send_row_sizes[q+r] = m[vector_exchange_send[j+2+r]].Size(); + total_rows_send += m[vector_exchange_send[j+2+r]].Size(); + } + GUARD_MPI(MPI_Isend(&send_row_sizes[q],vector_exchange_send[j+1],INMOST_MPI_DATA_ENUM_TYPE,vector_exchange_send[j],3*size+rank,comm,&requests[vector_exchange_recv[0]+k])); //recv rows + //remember processor numbers here + q += vector_exchange_send[j+1]; + j += vector_exchange_send[j+1]+2; + } + send_row_data.clear(); + send_row_data.reserve(total_rows_send); + + + j = 1; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_send[0]; k++) //accumulate data in array + { + for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_send[j+1]; r++) + send_row_data.insert(send_row_data.end(),m[vector_exchange_send[j+2+r]].Begin(),m[vector_exchange_send[j+2+r]].End()); + j += vector_exchange_send[j+1]+2; + } + + + //replace by mpi_waitsome + if( vector_exchange_recv[0]+vector_exchange_send[0] > 0 ) + GUARD_MPI(MPI_Waitall(vector_exchange_recv[0]+vector_exchange_send[0],&requests[0],MPI_STATUSES_IGNORE)); + + + j = 1; + q = 0; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //compute total size of data to receive + { + for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_recv[j+1]; r++) + total_rows_recv += recv_row_sizes[q+r]; + q += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1]+2; + } + recv_row_data.resize(total_rows_recv); + j = 1; + q = 0; + f = 0; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //receive row data + { + INMOST_DATA_ENUM_TYPE local_size = 0; + for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_recv[j+1]; r++) + local_size += recv_row_sizes[q+r]; + GUARD_MPI(MPI_Irecv(&recv_row_data[f],local_size,Sparse::GetRowEntryType(),vector_exchange_recv[j],4*size+vector_exchange_recv[j],comm,&requests[k])); + q += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1]+2; + f += local_size; + } + + + j = 1; + q = 0; + f = 0; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_send[0]; k++) //receive row data + { + INMOST_DATA_ENUM_TYPE local_size = 0; + for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_send[j+1]; r++) + local_size += send_row_sizes[q+r]; + GUARD_MPI(MPI_Isend(&send_row_data[f],local_size,Sparse::GetRowEntryType(),vector_exchange_send[j],4*size+rank,comm,&requests[k+vector_exchange_recv[0]])); + q += vector_exchange_send[j+1]; + j += vector_exchange_send[j+1]+2; + f += local_size; + } + + + local_start = local_end; + m.SetInterval(local_matrix_begin,ext_pos); + local_end = ext_pos; + if( vector_exchange_recv[0]+vector_exchange_send[0] > 0 ) + GUARD_MPI(MPI_Waitall(vector_exchange_recv[0]+vector_exchange_send[0],&requests[0],MPI_STATUSES_IGNORE)); + j = 1; + q = 0; + f = 0; + for(INMOST_DATA_ENUM_TYPE k = 0; k < vector_exchange_recv[0]; k++) //extend matrix + { + for(INMOST_DATA_ENUM_TYPE r = 0; r < vector_exchange_recv[j+1]; r++) + { + m[global_to_local[vector_exchange_recv[j+2+r]]] = Sparse::Row(&recv_row_data[f],&recv_row_data[f]+recv_row_sizes[q+r]); + f += recv_row_sizes[q+r]; + } + q += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1]+2; + } + } + //std::cout << it << "/" << overlap << " done" << std::endl; + } + two[0] = local_matrix_begin; + two[1] = local_end; + GUARD_MPI(MPI_Allgather(two,2,INMOST_MPI_DATA_ENUM_TYPE,&global_overlap[0],2,INMOST_MPI_DATA_ENUM_TYPE,comm)); + //std::cout << __FUNCTION__ << " done" << std::endl; #endif -#if defined(HAVE_SOLVER_K3BIILU2) - if( _pack == K3BIILU2 ) - { - bool modified_pattern = ModifiedPattern; - //~ if( A.comm != comm ) throw DifferentCommunicatorInSolver; - if( matrix_data == NULL ) - { - MatrixInitDataK3biilu2(&matrix_data,A.GetCommunicator(),A.GetName().c_str()); - modified_pattern = true; - } - if( modified_pattern ) - { - global_size = local_size = A.Size(); - - MatrixDestroyDataK3biilu2(&matrix_data); - MatrixInitDataK3biilu2(&matrix_data,A.GetCommunicator(),A.GetName().c_str()); - INMOST_DATA_ENUM_TYPE nnz = 0, k = 0, q = 1, shift = 0; - int nproc, myid; + } + + void Solver::OrderInfo::RestoreMatrix(Sparse::Matrix & m) + { + //restore matrix size + m.SetInterval(initial_matrix_begin,initial_matrix_end); + //restore indexes + for(Sparse::Matrix::iterator it = m.Begin(); it != m.End(); ++it) + for(Sparse::Row::iterator jt = it->Begin(); jt != it->End(); ++jt) + if( jt->first >= initial_matrix_end ) + jt->first = extended_indexes[jt->first-initial_matrix_end]; + m.isParallel() = false; + have_matrix = false; #if defined(USE_MPI) - MPI_Comm_size(A.GetCommunicator(),&nproc); - MPI_Comm_rank(A.GetCommunicator(),&myid); -#else - nproc = 1; - myid = 0; + if( comm != INMOST_MPI_COMM_WORLD ) + { + MPI_Comm_free(&comm); + comm = INMOST_MPI_COMM_WORLD; + } #endif - int * ibl = (int *)malloc(sizeof(int)*(nproc+1)); - ibl[0] = 0; - int n = A.Size(); + //std::cout << __FUNCTION__ << std::endl; + } + + Solver::OrderInfo::~OrderInfo() + { #if defined(USE_MPI) - INMOST_DATA_ENUM_TYPE mbeg,mend; - A.GetInterval(mbeg,mend); - n = mend - mbeg; - int block_end = mend; - MPI_Allgather(&block_end,1,MPI_INT,&ibl[1],1,MPI_INT,A.GetCommunicator()); -#else - ibl[1] = n; + if( comm != INMOST_MPI_COMM_WORLD ) + MPI_Comm_free(&comm); #endif - int * ia = (int *)malloc(sizeof(int)*(n+1)); - for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) nnz += it->Size(); - int * ja = (int *)malloc(sizeof(int)*nnz); - double * values = (double *) malloc(sizeof(double)*nnz); - ia[0] = shift; - for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); it++) - { - for(Sparse::Row::iterator jt = it->Begin(); jt != it->End(); jt++) - { - ja[k] = jt->first + 0; - values[k] = jt->second; - //std::cout<<"# q="<(matrix_data); - matrix_data = NULL; - } - local_size = A.Size(); + comm = other.comm; +#endif + rank = other.rank; + size = other.size; + initial_matrix_begin = other.initial_matrix_begin; + initial_matrix_end = other.initial_matrix_end; + local_vector_begin = other.local_vector_begin; + local_vector_end = other.local_vector_end; + local_matrix_begin = other.local_matrix_begin; + local_matrix_end = other.local_matrix_end; + have_matrix = other.have_matrix; + send_storage.resize(other.send_storage.size()); + recv_storage.resize(other.recv_storage.size()); + send_requests.resize(other.send_requests.size()); + recv_requests.resize(other.recv_requests.size()); + } + + Solver::OrderInfo & Solver::OrderInfo::operator =(OrderInfo const & other) + { #if defined(USE_MPI) - MPI_Allreduce(&local_size,&global_size,1,INMOST_MPI_DATA_ENUM_TYPE,MPI_SUM,comm); + if( other.comm == INMOST_MPI_COMM_WORLD ) + comm = INMOST_MPI_COMM_WORLD; + else MPI_Comm_dup(other.comm,&comm); #else - global_size = local_size; -#endif - //std::cout << Comm.MyPID() << " " << "local size " << local_size << " global size " << global_size << std::endl; - int k; - int imbeg = static_cast(mbeg); - int imend = static_cast(mend); - int * temporary = new int[imend-imbeg]; - for(k = imbeg; k < imend; ++k) temporary[k-imbeg] = k; - //std::cout << Comm.MyPID() << " " << "Creating Epetra_Map" << std::endl; - Epetra_Map Map(static_cast(global_size),static_cast(local_size),temporary,0,Comm); - k = 0; - for(k = imbeg; k < imend; ++k) temporary[k-imbeg] = A[k].Size(); - //std::cout << Comm.MyPID() << " " << "Creating Epetra_CrsMatrix" << std::endl; - Epetra_CrsMatrix * Matrix = new Epetra_CrsMatrix(Copy,Map,temporary,true); - matrix_data = static_cast(Matrix); - delete [] temporary; - refill = false; - } - { - assert(matrix_data); - Epetra_CrsMatrix * Matrix = static_cast(matrix_data); - unsigned max = 0; - for(Sparse::Matrix::iterator it = A.Begin(); it != A.End(); ++it) - if( it->Size() > max ) max = it->Size(); - int * col_positions = new int[max]; - double * col_values = new double[max]; - for(INMOST_DATA_ENUM_TYPE k = mbeg; k < mend; ++k) - { - INMOST_DATA_ENUM_TYPE m = 0; - for(INMOST_DATA_ENUM_TYPE i = 0; i < A[k].Size(); i++) - { - col_positions[m] = A[k].GetIndex(i); - col_values[m] = A[k].GetValue(i); - m++; - } - int ret; - if( refill ) - ret = Matrix->ReplaceGlobalValues(k,m,col_values,col_positions); - else - ret = Matrix->InsertGlobalValues(k,m,col_values,col_positions); - if( ret != 0 ) - std::cout << "Problem reported by Trilinos! return code " << ret << std::endl; - } - delete [] col_positions; - delete [] col_values; - Matrix->FillComplete(); - //std::stringstream str; - //str << "epetra" << Comm.MyPID() << ".mat"; - //std::fstream file(str.str(),std::ios::out); - //file << *Matrix; - //file.close(); - assert(solver_data); - Epetra_LinearProblem * problem = &static_cast *>(solver_data)->second; - problem->SetOperator(Matrix); - } - ok = true; - } -#endif - if (_pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILUC || _pack == INNER_MPTILU2) - { - - Sparse::Matrix * mat = new Sparse::Matrix(A); - info.PrepareMatrix(*mat, additive_schwartz_overlap); - IterativeMethod * sol = (IterativeMethod *)solver_data; - sol->ReplaceMAT(*mat); - if( matrix_data != NULL ) delete (Sparse::Matrix *)matrix_data; - matrix_data = (void *)mat; - - sol->RealParameter(":tau") = preconditioner_drop_tolerance; - sol->RealParameter(":tau2") = preconditioner_reuse_tolerance; - sol->EnumParameter(":scale_iters") = preconditioner_rescale_iterations; - - if( _pack == INNER_DDPQILUC ) - { - sol->RealParameter(":ddpq_tau") = preconditioner_ddpq_tolerance; - sol->EnumParameter(":reorder_nnz") = preconditioner_reorder_nonzero; - sol->EnumParameter(":estimator") = preconditioner_condition_estimation; - sol->EnumParameter(":ddpq_tau_adapt") = preconditioner_adapt_ddpq_tolerance; - } - else if( _pack == INNER_MPTILUC ) - { - sol->EnumParameter(":estimator") = preconditioner_condition_estimation; - } - else if( _pack == INNER_ILU2 ) sol->EnumParameter(":fill") = static_cast(preconditioner_fill_level); - - if( sizeof(KSOLVER) == sizeof(BCGSL_solver) ) - sol->EnumParameter("levels") = solver_gmres_substeps; - - if (!sol->isInitialized()) - { - sol->Initialize(); - } - ok = true; + comm = other.comm; +#endif + global_to_proc = other.global_to_proc; + global_overlap = other.global_overlap; + vector_exchange_recv = other.vector_exchange_recv; + vector_exchange_send = other.vector_exchange_send; + extended_indexes = other.extended_indexes; + rank = other.rank; + size = other.size; + initial_matrix_begin = other.initial_matrix_begin; + initial_matrix_end = other.initial_matrix_end; + local_vector_begin = other.local_vector_begin; + local_vector_end = other.local_vector_end; + local_matrix_begin = other.local_matrix_begin; + local_matrix_end = other.local_matrix_end; + have_matrix = other.have_matrix; + send_storage.resize(other.send_storage.size()); + recv_storage.resize(other.recv_storage.size()); + send_requests.resize(other.send_requests.size()); + recv_requests.resize(other.recv_requests.size()); + return *this; + } - } - if(!ok) throw NotImplemented; - } -#if defined(ACCELERATED_CONDEST) - INMOST_DATA_REAL_TYPE Solver::Condest(INMOST_DATA_REAL_TYPE tol, INMOST_DATA_ENUM_TYPE maxiter) - { - if( matrix_data == NULL ) throw MatrixNotSetInSolver; - if( _pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILU2 || _pack == INNER_MPTILUC ) + INMOST_DATA_ENUM_TYPE Solver::OrderInfo::GetProcessor(INMOST_DATA_ENUM_TYPE gind) const { - Sparse::Matrix & A = *(Sparse::Matrix *)matrix_data; - //IterativeMethod & sol = *(IterativeMethod *)solver_data; - INMOST_DATA_ENUM_TYPE lbeg, lend, l, iter; - INMOST_DATA_REAL_TYPE norm, sum[2], norm_prev, lambda_min, lambda_max; - bool diverged_max = false, diverged_min = false; - info.GetLocalRegion(info.GetRank(),lbeg,lend); - Sparse::Vector v, Av; - info.PrepareVector(v); - info.PrepareVector(Av); - //Set v to random - norm = 0; - for(l = lbeg; l < lend; ++l) - { - v[l] = rand()/static_cast(RAND_MAX); - norm += v[l]*v[l]; - } - info.Integrate(&norm,1); - norm_prev = 0.0; - norm = sqrt(norm); - for(l = lbeg; l < lend; ++l) v[l] /= norm; - //Compute maximum eigenvalue - iter = 0; - while( fabs((norm-norm_prev)/norm) > tol && iter < maxiter) - { - info.Update(v); -#if defined(USE_OMP) -#pragma omp parallel -#endif - A.MatVec(1.0,v,0.0,Av); - norm_prev = norm; - sum[0] = sum[1] = 0.0; - for(l = lbeg; l < lend; ++l) - { - sum[0] += v[l]*Av[l]; - sum[1] += v[l]*v[l]; - } - info.Integrate(sum,2); - norm = fabs(sum[0])/sum[1]; - for(l = lbeg; l < lend; ++l) v[l] = Av[l]/norm; -#if defined(PRINT_CONDEST) - std::cout << "iteration " << iter << " norm " << norm << std::endl; -#endif - iter++; - } -#if defined(PRINT_CONDEST) - std::cout << "lambda_max " << norm << std::endl; -#endif - if( iter == maxiter ) - { - diverged_max = true; - std::cout << "Max not converged" << std::endl; - } - lambda_max = norm; - //Set v to random - norm = 0; - for(l = lbeg; l < lend; ++l) - { - v[l] = rand()/static_cast(RAND_MAX); - norm += v[l]*v[l]; - } - info.Integrate(&norm,1); - norm_prev = 0.0; - norm = sqrt(norm); - for(l = lbeg; l < lend; ++l) v[l] /= norm; - //Compute minimal eigenvalue - iter = 0; - while( fabs((norm-norm_prev)/norm) > tol && iter < maxiter) - { - info.Update(v); - Solve(v,Av); - norm_prev = norm; - sum[0] = sum[1] = 0; - for(l = lbeg; l < lend; ++l) - { - sum[0] += v[l]*Av[l]; - sum[1] += v[l]*v[l]; - } - info.Integrate(sum,2); - norm = fabs(sum[0])/sum[1]; - for(l = lbeg; l < lend; ++l) v[l] = Av[l]/norm; -#if defined(PRINT_CONDEST) - std::cout << "iteration " << iter << " norm " << norm << "\t\t" << std::endl; -#endif - iter++; - } -#if defined(PRINT_CONDEST) - std::cout << "lambda_min " << 1.0/norm << std::endl; -#endif - if( iter == maxiter ) - { - diverged_min = true; - std::cout << "Min not converged" << std::endl; - } - lambda_min = 1.0/norm; - if( diverged_max || diverged_min ) - return 1.0e+100; -#if defined(PRINT_CONDEST) - std::cout << "Condest: " << lambda_max /lambda_min << std::endl; -#endif - return lambda_max/lambda_min; + assert(have_matrix); + storage_type::const_iterator find = std::lower_bound(global_to_proc.begin(),global_to_proc.end(),gind); + assert(find != global_to_proc.end()); + if( (*find) == gind && find+1 != global_to_proc.end()) return static_cast(find - global_to_proc.begin()); + else return static_cast(find - global_to_proc.begin())-1; } - else + void Solver::OrderInfo::GetOverlapRegion(INMOST_DATA_ENUM_TYPE proc, INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const { - throw -1; //other packages are not supported yet + assert(have_matrix); + mbeg = global_overlap[proc*2+0]; + mend = global_overlap[proc*2+1]; } - } -#else - INMOST_DATA_REAL_TYPE Solver::Condest(INMOST_DATA_REAL_TYPE tol, INMOST_DATA_ENUM_TYPE maxiter) - { - if( matrix_data == NULL ) throw MatrixNotSetInSolver; - if( _pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILU2 || _pack == INNER_MPTILUC ) + void Solver::OrderInfo::GetLocalRegion(INMOST_DATA_ENUM_TYPE proc, INMOST_DATA_ENUM_TYPE & mbeg, INMOST_DATA_ENUM_TYPE & mend) const { - Sparse::Matrix & A = *(Sparse::Matrix *)matrix_data; - //IterativeMethod & sol = *(IterativeMethod *)solver_data; - INMOST_DATA_ENUM_TYPE lbeg, lend, l, iter; - INMOST_DATA_REAL_TYPE norm, norm_prev, lambda_min, lambda_max; - bool diverged_max = false, diverged_min = false; - info.GetLocalRegion(info.GetRank(),lbeg,lend); - Sparse::Vector v, Av; - info.PrepareVector(v); - info.PrepareVector(Av); - //Set v to random - norm = 0; - for(l = lbeg; l < lend; ++l) - { - v[l] = rand()/static_cast(RAND_MAX); - norm += v[l]*v[l]; - } - info.Integrate(&norm,1); - norm_prev = 0.0; - norm = sqrt(norm); - for(l = lbeg; l < lend; ++l) v[l] /= norm; - //Compute maximum eigenvalue - iter = 0; - while( fabs(norm-norm_prev)/norm > tol && iter < maxiter) - { - info.Update(v); + assert(have_matrix); + mbeg = global_to_proc[proc+0]; + mend = global_to_proc[proc+1]; + } + + + void Solver::OrderInfo::Update(Sparse::Vector & x) + { + //std::cout << __FUNCTION__ << " start" << std::endl; +#if defined(USE_MPI) + if( GetSize() == 1 ) return; #if defined(USE_OMP) -#pragma omp parallel -#endif - A.MatVec(1.0,v,0.0,Av); - v.Swap(Av); - norm_prev = norm; - norm = 0.0; - for(l = lbeg; l < lend; ++l) norm += v[l]*v[l]; - info.Integrate(&norm,1); - norm = sqrt(norm); - for(l = lbeg; l < lend; ++l) v[l] /= norm; -#if defined(PRINT_CONDEST) - std::cout << "iteration " << iter << " norm " << norm << std::endl; -#endif - iter++; - } -#if defined(PRINT_CONDEST) - std::cout << "lambda_max " << norm << std::endl; -#endif - if( iter == maxiter ) - { - norm = std::max(norm,norm_prev); - //diverged_max = true; - //std::cout << "Max not converged" << std::endl; - } - lambda_max = norm; - //Set v to random - norm = 0; - for(l = lbeg; l < lend; ++l) - { - v[l] = rand()/static_cast(RAND_MAX); - norm += v[l]*v[l]; - } - info.Integrate(&norm,1); - norm_prev = 0.0; - norm = sqrt(norm); - for(l = lbeg; l < lend; ++l) v[l] /= norm; - //Compute minimal eigenvalue - iter = 0; - while( fabs(norm-norm_prev)/norm > tol && iter < maxiter) - { - info.Update(v); - Solve(v,Av); - v.Swap(Av); - norm_prev = norm; - norm = 0.0; - for(l = lbeg; l < lend; ++l) norm += v[l]*v[l]; - info.Integrate(&norm,1); - norm = sqrt(norm); - for(l = lbeg; l < lend; ++l) v[l] /= norm; -#if defined(PRINT_CONDEST) - std::cout << "iteration " << iter << " norm " << norm << "\t\t" << std::endl; -#endif - iter++; - } -#if defined(PRINT_CONDEST) - std::cout << "lambda_min " << 1.0/norm << std::endl; +#pragma omp single #endif - if( iter == maxiter ) - { - norm = std::max(norm,norm_prev); - //diverged_min = true; - //std::cout << "Min not converged" << std::endl; - } - lambda_min = 1.0/norm; - if( diverged_max || diverged_min ) - return 1.0e+100; -#if defined(PRINT_CONDEST) - std::cout << "Condest: " << lambda_max /lambda_min << std::endl; + { + //use MPI_Put/MPI_Get to update vector + assert(x.isParallel()); //the vector was prepared + INMOST_DATA_ENUM_TYPE i, j = 1, k, l = 0; + int ierr; + for(i = 0; i < vector_exchange_recv[0]; i++) + { + //std::cout << GetRank() << " MPI_Irecv size " << vector_exchange_recv[j+1] << " dest " << vector_exchange_recv[j] << " tag " << vector_exchange_recv[j]*size+rank << std::endl; + GUARD_MPI(MPI_Irecv(&recv_storage[l],vector_exchange_recv[j+1],INMOST_MPI_DATA_REAL_TYPE,vector_exchange_recv[j],vector_exchange_recv[j]*size+rank,comm,&recv_requests[i])); + l += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1] + 2; + } + j = 1, l = 0; + for(i = 0; i < vector_exchange_send[0]; i++) + { + //std::cout << GetRank() << " MPI_Isend size " << vector_exchange_send[j+1] << " dest " << vector_exchange_send[j] << " tag " << rank*size+vector_exchange_send[j] << std::endl; + for(k = 0; k < vector_exchange_send[j+1]; k++) + send_storage[l+k] = x[vector_exchange_send[k+j+2]]; + GUARD_MPI(MPI_Isend(&send_storage[l],vector_exchange_send[j+1],INMOST_MPI_DATA_REAL_TYPE,vector_exchange_send[j],rank*size+vector_exchange_send[j],comm,&send_requests[i])); + l += vector_exchange_send[j+1]; + j += vector_exchange_send[j+1] + 2; + } + if( vector_exchange_recv[0] > 0 ) + { + GUARD_MPI(MPI_Waitall(static_cast(recv_requests.size()),&recv_requests[0],MPI_STATUSES_IGNORE)); + j = 1, l = 0; + for(i = 0; i < vector_exchange_recv[0]; i++) + { + for(k = 0; k < vector_exchange_recv[j+1]; k++) + x[vector_exchange_recv[k+j+2]] = recv_storage[l+k]; + l += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1] + 2; + } + } + if( vector_exchange_send[0] > 0 ) + { + GUARD_MPI(MPI_Waitall(static_cast(send_requests.size()),&send_requests[0],MPI_STATUSES_IGNORE)); + } + } +#else + (void) x; #endif - return lambda_max/lambda_min; + //std::cout << __FUNCTION__ << " end" << std::endl; } - else + void Solver::OrderInfo::Accumulate(Sparse::Vector & x) { - throw -1; //other packages are not supported yet - } - } -#endif - bool Solver::Solve(Sparse::Vector & RHS, Sparse::Vector & SOL) - { - //check the data - if( matrix_data == NULL ) throw MatrixNotSetInSolver; - if( RHS.GetCommunicator() != comm || SOL.GetCommunicator() != comm ) throw DifferentCommunicatorInSolver; - INMOST_DATA_ENUM_TYPE vbeg,vend; - RHS.GetInterval(vbeg,vend); - if( RHS.Size() != SOL.Size() ) - { - if( SOL.Size() == 0 ) - { - SOL.SetInterval(vbeg,vend); - for(Sparse::Vector::iterator ri = SOL.Begin(); ri != SOL.End(); ++ri) *ri = 0.0; - } - else throw InconsistentSizesInSolver; - } - //run the solver -#if defined(USE_SOLVER_PETSC) - if( _pack == PETSc ) - { - if( rhs_data == NULL ) - VectorInitDataPetsc(&rhs_data,RHS.GetCommunicator(),RHS.GetName().c_str()); - VectorPreallocatePetsc(rhs_data,local_size,global_size); - - if( solution_data == NULL ) - VectorInitDataPetsc(&solution_data,SOL.GetCommunicator(),SOL.GetName().c_str()); - VectorPreallocatePetsc(solution_data,local_size,global_size); - - - int * positions = new int[local_size]; - double * values = new double[local_size]; - { - unsigned k = 0; - for(Sparse::Vector::iterator it = RHS.Begin(); it != RHS.End(); ++it) - { - positions[k] = vbeg+k; - values[k] = *it; - k++; - } - VectorFillPetsc(rhs_data,local_size,positions,values); - VectorFinalizePetsc(rhs_data); - - k = 0; - for(Sparse::Vector::iterator it = SOL.Begin(); it != SOL.End(); ++it) - { - values[k] = *it; - k++; - } - VectorFillPetsc(solution_data,local_size,positions,values); - VectorFinalizePetsc(solution_data); - } - if( petsc_database_file == "" ) //set parameters if no file is set - { - SolverSetTolerancesPetsc(solver_data,relative_tolerance,absolute_tolerance,divergence_tolerance,maximum_iterations); - } - bool result = SolverSolvePetsc(solver_data,rhs_data,solution_data); - if( result ) - { - VectorLoadPetsc(solution_data,local_size,positions,values); - unsigned k = 0; - for(Sparse::Vector::iterator it = SOL.Begin(); it != SOL.End(); ++it) - { - *it = values[k]; - k++; - } - } - delete [] positions; - delete [] values; - last_resid = SolverResidualNormPetsc(solver_data); - last_it = SolverIterationNumberPetsc(solver_data); - return_reason = std::string(SolverConvergedReasonPetsc(solver_data)); - return result; - } -#endif -#if defined(USE_SOLVER_ANI) - if( _pack == ANI ) - { - if( rhs_data == NULL ) - VectorInitDataAni(&rhs_data,RHS.GetCommunicator(),RHS.GetName().c_str()); - VectorPreallocateAni(rhs_data,local_size); - - if( solution_data == NULL ) - VectorInitDataAni(&solution_data,SOL.GetCommunicator(),SOL.GetName().c_str()); - VectorPreallocateAni(solution_data,local_size); - { - VectorFillAni(rhs_data,&RHS[vbeg]); - VectorFinalizeAni(rhs_data); - - VectorFillAni(solution_data,&SOL[vbeg]); - VectorFinalizeAni(solution_data); - } - bool result = SolverSolveAni(solver_data,rhs_data,solution_data); - if( result ) VectorLoadAni(solution_data,&SOL[vbeg]); - last_resid = SolverResidualNormAni(solver_data); - last_it = SolverIterationNumberAni(solver_data); - return_reason = "Unspecified for ANI"; - return result; - } -#endif -#if defined(HAVE_SOLVER_FCBIILU2) - if( _pack == FCBIILU2 ) - { - if( rhs_data == NULL ) - VectorInitDataFcbiilu2(&rhs_data,RHS.GetCommunicator(),RHS.GetName().c_str()); - VectorPreallocateFcbiilu2(rhs_data,local_size); - - if( solution_data == NULL ) - VectorInitDataFcbiilu2(&solution_data,SOL.GetCommunicator(),SOL.GetName().c_str()); - VectorPreallocateFcbiilu2(solution_data,local_size); - { - VectorFillFcbiilu2(rhs_data,&RHS[vbeg]); - VectorFinalizeFcbiilu2(rhs_data); - - VectorFillFcbiilu2(solution_data,&SOL[vbeg]); - VectorFinalizeFcbiilu2(solution_data); - } - bool result = SolverSolveFcbiilu2(solver_data,rhs_data,solution_data); - if( result ) VectorLoadFcbiilu2(solution_data,&SOL[vbeg]); - last_resid = SolverResidualNormFcbiilu2(solver_data); - last_it = SolverIterationNumberFcbiilu2(solver_data); - //return_reason = std::string(SolverConvergedReasonFcbiilu2(solver_data)); - return_reason = "Unspecified for FCBIILU2"; - return result; - } -#endif -#if defined(HAVE_SOLVER_K3BIILU2) - if( _pack == K3BIILU2 ) - { - if( rhs_data == NULL ) - VectorInitDataK3biilu2(&rhs_data,RHS.GetCommunicator(),RHS.GetName().c_str()); - VectorPreallocateK3biilu2(rhs_data,local_size); - - if( solution_data == NULL ) - VectorInitDataK3biilu2(&solution_data,SOL.GetCommunicator(),SOL.GetName().c_str()); - VectorPreallocateK3biilu2(solution_data,local_size); - { - VectorFillK3biilu2(rhs_data,&RHS[vbeg]); - VectorFinalizeK3biilu2(rhs_data); - - VectorFillK3biilu2(solution_data,&SOL[vbeg]); - VectorFinalizeK3biilu2(solution_data); - } - bool result = SolverSolveK3biilu2(solver_data,rhs_data,solution_data); - if( result ) VectorLoadK3biilu2(solution_data,&SOL[vbeg]); - last_resid = SolverResidualNormK3biilu2(solver_data); - last_it = SolverIterationNumberK3biilu2(solver_data); - //return_reason = std::string(SolverConvergedReasonK3biilu2(solver_data)); - return_reason = "Unspecified for K3BIILU2"; - return result; - } -#endif -#if defined(USE_SOLVER_TRILINOS) - if(_pack == Trilinos_Aztec || - _pack == Trilinos_ML || - _pack == Trilinos_Ifpack) - { - assert(matrix_data); - std::string name = static_cast *>(solver_data)->first; - Epetra_LinearProblem * problem = &static_cast *>(solver_data)->second; - Epetra_CrsMatrix * Matrix = static_cast(matrix_data); - Epetra_Vector VectorRHS(View,Matrix->Map(),&*RHS.Begin()); - Epetra_Vector VectorSOL(View,Matrix->Map(),&*SOL.Begin()); - problem->SetRHS(&VectorRHS); - problem->SetLHS(&VectorSOL); - std::string specific_database_file = ""; - if( _pack == Trilinos_Aztec ) - specific_database_file = trilinos_aztec_database_file; - else if( _pack == Trilinos_ML ) - specific_database_file = trilinos_ml_database_file; - else if( _pack == Trilinos_Ifpack ) - specific_database_file = trilinos_ifpack_database_file; - - bool have_params = specific_database_file != ""; - const Teuchos::RCP top_level_params = Teuchos::createParameterList(); - Teuchos::ParameterList local_list; - if( have_params ) - { - Teuchos::updateParametersFromXmlFileAndBroadcast(specific_database_file,top_level_params.ptr(),Teuchos::MpiComm(Teuchos::opaqueWrapper(RHS.GetCommunicator()))); - //top_level_params->print(std::cout,0,true,true); - if( !top_level_params->isSublist(name) ) - have_params = false; - else - { - local_list = top_level_params->sublist(name); - //std::cout << "Got local list for " << name << std::endl; - } - } - - - AztecOO AztecSolver(*problem); - - - if( have_params && local_list.isSublist("AztecOO")) - { - Teuchos::ParameterList AztecOOParams = local_list.sublist("AztecOO"); - if( AztecOOParams.isParameter("Max Iterations") ) - { - maximum_iterations = AztecOOParams.get("Max Iterations"); - //std::cout << "Got maximum iterations " << maximum_iterations << std::endl; - } - if( AztecOOParams.isParameter("Tolerance") ) - { - relative_tolerance = AztecOOParams.get("Tolerance"); - //std::cout << "Got tolerance " << relative_tolerance << std::endl; - } - if( AztecOOParams.isSublist("AztecOO Settings") ) - { - AztecSolver.SetParameters(AztecOOParams.sublist("AztecOO Settings")); - //std::cout << "Submit Aztec settings" << std::endl; - } - } - else - { - AztecSolver.SetAztecOption(AZ_diagnostics,AZ_none); - AztecSolver.SetAztecOption(AZ_output,AZ_none); - AztecSolver.SetAztecOption(AZ_solver,AZ_bicgstab); - AztecSolver.SetAztecOption(AZ_overlap,additive_schwartz_overlap); - } - - void * precinfo = NULL; - if( _pack == Trilinos_Aztec ) - { - if( !have_params ) - { - AztecSolver.SetAztecParam(AZ_drop,preconditioner_drop_tolerance); - AztecSolver.SetAztecParam(AZ_ilut_fill,preconditioner_fill_level); - //AztecSolver.SetAztecOption(AZ_solver,AZ_tfqmr); - //AztecSolver.SetAztecOption(AZ_precond,AZ_Neumann); - //AztecSolver.SetAztecOption(AZ_poly_ord,3); - } - else - { - //should be set automatically - } - } - else if( _pack == Trilinos_ML ) - { - Teuchos::ParameterList List; - if( have_params && local_list.isSublist("ML") && local_list.sublist("ML").isSublist("ML Settings") ) - { - List = local_list.sublist("ML").sublist("ML Settings"); - } - else - { - ML_Epetra::SetDefaults("SA",List); - List.set("max levels",6); - List.set("increasing or decreasing","decreasing"); - //List.set("aggreagation: type", "MIS"); - //List.set("coarse: type", "Amesos-KLU"); - } - ML_Epetra::MultiLevelPreconditioner * Prec = new ML_Epetra::MultiLevelPreconditioner(*Matrix,List,true); - AztecSolver.SetPrecOperator(Prec); - precinfo = Prec; - } - else if( _pack == Trilinos_Ifpack ) - { - Ifpack * Factory = new Ifpack(); - Ifpack_Preconditioner * Prec; - std::string PrecType = "ILU"; - if( have_params && local_list.isSublist("Ifpack") ) - { - Teuchos::ParameterList ifpacklist = local_list.sublist("Ifpack"); - if( ifpacklist.isParameter("Prec Type") ) - { - PrecType = ifpacklist.get("Prec Type"); - //std::cout << "Got preconditioner type " << PrecType << std::endl; - } - if( ifpacklist.isParameter("Overlap") ) - { - additive_schwartz_overlap = ifpacklist.get("Overlap"); - //std::cout << "Got overlap " << additive_schwartz_overlap << std::endl; - } - } - Prec = Factory->Create(PrecType,Matrix,additive_schwartz_overlap); - Teuchos::ParameterList List; - if( have_params && local_list.isSublist("Ifpack") && local_list.sublist("Ifpack").isSublist("Ifpack Settings") ) - { - List = local_list.sublist("Ifpack").sublist("Ifpack Settings"); - //std::cout << "Submit settings to ifpack" << std::endl; - } - else - List.set("fact: level-of-fill",static_cast(preconditioner_fill_level)); - Prec->SetParameters(List); - Prec->Initialize(); - Prec->Compute(); - AztecSolver.SetPrecOperator(Prec); - precinfo = Factory; - } - AztecSolver.Iterate(maximum_iterations,relative_tolerance); - if( _pack == Trilinos_ML ) - delete static_cast(precinfo); - else if( _pack == Trilinos_Ifpack ) - delete static_cast(precinfo); - const double * stats = AztecSolver.GetAztecStatus(); - bool ret = true; - switch(static_cast(stats[AZ_why])) - { - case AZ_normal: - return_reason = "User requested convergence criteria is satisfied."; - break; - case AZ_param: - return_reason = "User requested option is not availible."; - ret = false; - break; - case AZ_breakdown: - return_reason = "Numerical breakdown occurred."; - ret = false; - break; - case AZ_loss: - return_reason = "Numerical loss precision occurred."; - ret = false; - break; - case AZ_ill_cond: - return_reason = "The Hessenberg matrix within GMRES is illconditioned. " - "This could be caused by a number " - "of reasons. For example, the preconditioning " - "matrix could be nearly singular due to an unstable " - "factorization (note: pivoting is not implemented " - "in any of the incomplete factorizations). " - "Ill-conditioned Hessenberg matrices could also " - "arise from a singular application matrix. In this " - "case, GMRES tries to compute a least-squares " - "solution."; - ret = false; - break; - case AZ_maxits: - return_reason = "Maximum iterations taken without convergence."; - ret = false; - break; - default: - { - std::stringstream str; - str << "reason code " << static_cast(stats[AZ_why]) << " was not specified in manual by the time, reffer to Trilinos manual."; - return_reason = str.str(); - } - break; - } - last_it = AztecSolver.NumIters(); - last_resid = AztecSolver.TrueResidual(); - return ret; - } - if(_pack == Trilinos_Belos ) - { - assert(matrix_data); - std::string name = static_cast *>(solver_data)->first; - Epetra_LinearProblem * problem = &static_cast *>(solver_data)->second; - Epetra_CrsMatrix * Matrix = static_cast(matrix_data); - Epetra_Vector VectorRHS(View,Matrix->Map(),&*RHS.Begin()); - Epetra_Vector VectorSOL(View,Matrix->Map(),&*SOL.Begin()); - problem->SetRHS(&VectorRHS); - problem->SetLHS(&VectorSOL); - - bool have_params = trilinos_belos_database_file != ""; - const Teuchos::RCP top_level_params = Teuchos::createParameterList(); - if( have_params ) Teuchos::updateParametersFromXmlFileAndBroadcast(trilinos_belos_database_file,top_level_params.ptr(),Teuchos::MpiComm(Teuchos::opaqueWrapper(RHS.GetCommunicator()))); - - Teuchos::RCP List = Teuchos::rcp(new Teuchos::ParameterList); - - if( have_params && top_level_params->isSublist(name) && top_level_params->sublist(name).isSublist("Belos") ) - *List = top_level_params->sublist(name).sublist("Belos"); - else - { - List->set("Num Blocks",100); - List->set("Block Size",1); - List->set("Maximum Iterations",static_cast(maximum_iterations)); - List->set("Maximum Restarts",20); - List->set("Convergence Tolerance",static_cast(relative_tolerance)); - } - //int verbosity = Belos::Warnings + Belos::Errors + Belos::StatusTestDetails + Belos::Debug + Belos::FinalSummary + Belos::TimingDetails; - //List->set("Verbosity",verbosity); - Teuchos::RCP > Problem = - Teuchos::rcp(new Belos::LinearProblem); - Problem->setLHS(Teuchos::rcp_implicit_cast(Teuchos::rcp(&VectorSOL,false))); - Problem->setRHS(Teuchos::rcp_implicit_cast(Teuchos::rcp(&VectorRHS,false))); - Problem->setOperator(Teuchos::rcp_implicit_cast(Teuchos::rcp(Matrix,false))); - - /* - //This don't work - Teuchos::ParameterList MLList; - ML_Epetra::SetDefaults("SA",MLList); - MLList.set("max levels",6); - MLList.set("increasing or decreasing","decreasing"); - //List.set("aggreagation: type", "MIS"); - //List.set("coarse: type", "Amesos-KLU"); - ML_Epetra::MultiLevelPreconditioner * Prec = new ML_Epetra::MultiLevelPreconditioner(*Matrix,MLList,true); - Prec->ComputePreconditioner(); - Problem->setLeftPrec(Teuchos::rcp_implicit_cast(Teuchos::rcp(Prec,false))); - */ - - Problem->setProblem(); - - Teuchos::RCP< Belos::SolverManager > BelosSolver = - // Teuchos::rcp(new Belos::BlockCgSolMgr); - Teuchos::rcp(new Belos::BlockGmresSolMgr); - // Teuchos::rcp(new Belos::PseudoBlockGmresSolMgr); - BelosSolver->setParameters(List); - BelosSolver->setProblem(Problem); - Belos::ReturnType ret = BelosSolver->solve(); - last_it = BelosSolver->getNumIters(); - last_resid = BelosSolver->achievedTol(); - - //delete Prec; - - if( ret == Belos::Converged ) - { - return_reason = "Converged"; - return true; - } - else - { - std::stringstream reason_stream; - reason_stream << "Diverged "; - if( BelosSolver->isLOADetected() ) - reason_stream << "loss of accuracy detected "; - if( BelosSolver->getNumIters() >= 1000 ) - reason_stream << "maximum iteration number reached "; - if( BelosSolver->achievedTol() > 1.0e+6 ) - reason_stream << "divergence tolerance reached "; - return_reason = reason_stream.str(); - return false; - } - - } + //std::cout << __FUNCTION__ << " start" << std::endl; +#if defined(USE_MPI) + if( GetSize() == 1 ) return; +#if defined(USE_OMP) +#pragma omp single #endif -#if defined(USE_SOLVER_SUPERLU) - if(_pack == SUPERLU ) - { - int size = MatrixSizeSuperLU(solver_data); - double * inout = new double[size]; - int * remap = MatrixRemapArraySuperLU(solver_data); - int mbeg = RHS.GetFirstIndex(), mend = RHS.GetLastIndex(); - for(int k = 0; k < mend - mbeg; ++k) if( remap[k] != -1 ) inout[remap[k]] = RHS[k+mbeg]; - bool ret = SolverSolveSuperLU(solver_data,inout); - for(int k = 0; k < mend - mbeg; ++k) if( remap[k] != -1 ) SOL[k+mbeg] = inout[remap[k]]; - delete [] inout; - last_it = 1; - last_resid = 0; - return_reason = SolverConvergedReasonSuperLU(solver_data); - return ret; - } + { + //use MPI_Put/MPI_Get to update vector + assert(x.isParallel()); //the vector was prepared + INMOST_DATA_ENUM_TYPE i, j = 1, k, l = 0; + int ierr; + for(i = 0; i < vector_exchange_send[0]; i++) + { + //std::cout << GetRank() << " MPI_Irecv size " << vector_exchange_send[j+1] << " dest " << vector_exchange_send[j] << " tag " << vector_exchange_send[j]*size+rank << std::endl; + GUARD_MPI(MPI_Irecv(&send_storage[l],vector_exchange_send[j+1],INMOST_MPI_DATA_REAL_TYPE,vector_exchange_send[j],vector_exchange_send[j]*size+rank,comm,&send_requests[i])); + l += vector_exchange_send[j+1]; + j += vector_exchange_send[j+1] + 2; + } + j = 1, l = 0; + for(i = 0; i < vector_exchange_recv[0]; i++) + { + for(k = 0; k < vector_exchange_recv[j+1]; k++) + recv_storage[l+k] = x[vector_exchange_recv[k+j+2]]; + //std::cout << GetRank() << " MPI_Isend size " << vector_exchange_recv[j+1] << " dest " << vector_exchange_recv[j] << " tag " << rank*size+vector_exchange_recv[j] << std::endl; + GUARD_MPI(MPI_Isend(&recv_storage[l],vector_exchange_recv[j+1],INMOST_MPI_DATA_REAL_TYPE,vector_exchange_recv[j],rank*size+vector_exchange_recv[j],comm,&recv_requests[i])); + l += vector_exchange_recv[j+1]; + j += vector_exchange_recv[j+1] + 2; + } + if( vector_exchange_send[0] > 0 ) + { + //std::cout << GetRank() << " Waitall send " << send_requests.size() << std::endl; + GUARD_MPI(MPI_Waitall(static_cast(send_requests.size()),&send_requests[0],MPI_STATUSES_IGNORE)); + j = 1, l = 0; + for(i = 0; i < vector_exchange_send[0]; i++) + { + for(k = 0; k < vector_exchange_send[j+1]; k++) + x[vector_exchange_send[k+j+2]] += send_storage[l+k]; + l += vector_exchange_send[j+1]; + j += vector_exchange_send[j+1] + 2; + } + } + if( vector_exchange_recv[0] > 0 ) + { + //std::cout << GetRank() << " Waitall recv " << recv_requests.size() << std::endl; + GUARD_MPI(MPI_Waitall(static_cast(recv_requests.size()),&recv_requests[0],MPI_STATUSES_IGNORE)); + } + } +#else + (void) x; #endif - if(_pack == INNER_ILU2 || _pack == INNER_DDPQILUC || _pack == INNER_MPTILUC || _pack == INNER_MPTILU2) - { - IterativeMethod * sol = static_cast(solver_data); - - sol->EnumParameter("maxits") = maximum_iterations; - sol->RealParameter("rtol") = relative_tolerance; - sol->RealParameter("atol") = absolute_tolerance; - sol->RealParameter("divtol") = divergence_tolerance; - - bool ret = sol->Solve(RHS,SOL); - last_it = sol->GetIterations(); - last_resid = sol->GetResidual(); - return_reason = sol->GetReason(); - return ret; - } - throw NotImplemented; - } - - std::string Solver::GetReason() - { - return return_reason; - } - - INMOST_DATA_ENUM_TYPE Solver::Iterations() - { - return last_it; - } - INMOST_DATA_REAL_TYPE Solver::Residual() - { - return last_resid; - } - - INMOST_DATA_REAL_TYPE Solver::GetConditionNumberL() - { - if(_pack == INNER_MPTILUC ) - { - return static_cast(solver_data)->RealParameter(":condition_number_L"); + //std::cout << __FUNCTION__ << " end" << std::endl; } - else return 0.0; - } - INMOST_DATA_REAL_TYPE Solver::GetConditionNumberU() - { - if(_pack == INNER_MPTILUC ) + /* + void Solver::OrderInfo::ScalarProd(Vector const & left, Vector const & right, INMOST_DATA_ENUM_TYPE index_begin, INMOST_DATA_ENUM_TYPE index_end, INMOST_DATA_REAL_TYPE & sum) const { - return static_cast(solver_data)->RealParameter(":condition_number_U"); + INMOST_DATA_INTEGER_TYPE ibeg = index_begin, iend = index_end; +#if defined(USE_OMP) +#pragma omp for reduction(+:sum) +#endif + for(INMOST_DATA_INTEGER_TYPE i = ibeg; i < iend; ++i) + { + sum += left[i]*right[i]; + } + Integrate(&sum,1); } - else return 0.0; - } + */ + } -#endif - diff --git a/Source/Solver/solver_inner/CMakeLists.txt b/Source/Solver/solver_inner/CMakeLists.txt new file mode 100644 index 0000000..a68f299 --- /dev/null +++ b/Source/Solver/solver_inner/CMakeLists.txt @@ -0,0 +1,7 @@ +set(HEADER ${HEADER} ${CMAKE_CURRENT_SOURCE_DIR}/solver_prototypes.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/solver_bcgsl.hpp) + +add_subdirectory(solver_ilu2) + +set(SOURCE ${SOURCE} PARENT_SCOPE) +set(HEADER ${HEADER} PARENT_SCOPE) \ No newline at end of file diff --git a/Source/Solver/solver_inner/solver_bcgsl.hpp b/Source/Solver/solver_inner/solver_bcgsl.hpp new file mode 100644 index 0000000..817bb0e --- /dev/null +++ b/Source/Solver/solver_inner/solver_bcgsl.hpp @@ -0,0 +1,1868 @@ + +#ifndef __SOLVER_BCGS__ +#define __SOLVER_BCGS__ + +//\todo +// 1. comply solvers with Method prototype, after TODO in solver_prototypes.hpp is done +// 2. Implement tricks from Read/solver/bcgsl/download.pdf with convex update and true residual correction +// 3. Detect numerical accuracy breakdown - when preconditioned residual is too far from true residual (probably 2 will fix). + +#include "inmost_solver.h" + +#define PERTURBATE_RTILDE +//#define CONVEX_COMBINATION +#define PSEUDOINVERSE // same trick as in petsc with pseudoinverse +//#define USE_LAPACK_SVD // use lapack's dgesvd routine instead of built-in svdnxn + +//#if !defined(NDEBUG) +#define REPORT_RESIDUAL +//#endif +//#define USE_OMP + + +namespace INMOST +{ + //lapack svd +#if defined(PSEUDOINVERSE) +#if defined(USE_LAPACK_SVD) + extern "C" + { + void dgesvd_(char*,char*,int*,int*,double*,int*,double*,double*,int*,double*,int*,double*,int*,int*); + } +#else + //SVD adopted from http://www.public.iastate.edu/~dicook/JSS/paper/code/svd.c + static INMOST_DATA_REAL_TYPE SIGNFUNC(INMOST_DATA_REAL_TYPE a, INMOST_DATA_REAL_TYPE b) { return b >= 0.0 ? fabs(a) : -fabs(a); } + static INMOST_DATA_REAL_TYPE MAXFUNC(INMOST_DATA_REAL_TYPE x,INMOST_DATA_REAL_TYPE y) { return x > y? x : y; } + static INMOST_DATA_REAL_TYPE PYTHAG(INMOST_DATA_REAL_TYPE a, INMOST_DATA_REAL_TYPE b) + { + INMOST_DATA_REAL_TYPE at = fabs(a), bt = fabs(b), ct, result; + if (at > bt) { ct = bt / at; result = sqrt(at) * sqrt(at + ct * bt); } + else if (bt > 0.0) { ct = at / bt; result = sqrt(bt) * sqrt(bt + ct * at); } + else result = 0.0; + return(result); + } + static int svdnxn(INMOST_DATA_REAL_TYPE * pa,INMOST_DATA_REAL_TYPE * pu, INMOST_DATA_REAL_TYPE *pw, INMOST_DATA_REAL_TYPE * pv, const int n) + { + shell a(pa,n*n); + shell u(pu,n*n); + shell v(pv,n*n); + shell w(pw,n); + //std::copy(a.begin(),a.end(),u.begin()); + //memcpy(u,a,sizeof(INMOST_DATA_REAL_TYPE)*n*n); + int flag, i, its, j, jj, k, l, nm; + INMOST_DATA_REAL_TYPE c, f, h, s, x, y, z; + INMOST_DATA_REAL_TYPE anorm = 0.0, g = 0.0, scale = 0.0; + dynarray rv1; + rv1.resize(n); + // Householder reduction to bidiagonal form + for (i = 0; i < n*n; ++i) u[i] = a[i]; + for (i = 0; i < n; i++) + { + // left-hand reduction + l = i + 1; + rv1[i] = scale * g; + g = s = scale = 0.0; + if (i < n) + { + for (k = i; k < n; k++) + scale += fabs(u[k*n+i]); + if (scale) + { + for (k = i; k < n; k++) + { + u[k*n+i] = u[k*n+i]/scale; + s += (u[k*n+i] * u[k*n+i]); + } + f = u[i*n+i]; + g = -SIGNFUNC(sqrt(s), f); + h = f * g - s; + u[i*n+i] = (f - g); + if (i != n - 1) + { + for (j = l; j < n; j++) + { + for (s = 0.0, k = i; k < n; k++) + s += (u[k*n+i] * u[k*n+j]); + f = s / h; + for (k = i; k < n; k++) + u[k*n+j] += (f * u[k*n+i]); + } + } + for (k = i; k < n; k++) + u[k*n+i] = (u[k*n+i]*scale); + } + } + w[i] = (scale * g); + + // right-hand reduction + g = s = scale = 0.0; + if (i < n && i != n - 1) + { + for (k = l; k < n; k++) + scale += fabs(u[i*n+k]); + if (scale) + { + for (k = l; k < n; k++) + { + u[i*n+k] = (u[i*n+k]/scale); + s += (u[i*n+k] * u[i*n+k]); + } + f = u[i*n+l]; + g = -SIGNFUNC(sqrt(s), f); + h = f * g - s; + u[i*n+l] = (f - g); + for (k = l; k < n; k++) + rv1[k] = u[i*n+k] / h; + if (i != n - 1) + { + for (j = l; j < n; j++) + { + for (s = 0.0, k = l; k < n; k++) + s += (u[j*n+k] * u[i*n+k]); + for (k = l; k < n; k++) + u[j*n+k] += (s * rv1[k]); + } + } + for (k = l; k < n; k++) + u[i*n+k] = (u[i*n+k]*scale); + } + } + anorm = MAXFUNC(anorm, (fabs(w[i]) + fabs(rv1[i]))); + } + + // accumulate the right-hand transformation + for (i = n - 1; i >= 0; i--) + { + if (i < n - 1) + { + if (g) + { + for (j = l; j < n; j++) + v[j*n+i] = ((u[i*n+j] / u[i*n+l]) / g); + // double division to avoid underflow + for (j = l; j < n; j++) + { + for (s = 0.0, k = l; k < n; k++) + s += (u[i*n+k] * v[k*n+j]); + for (k = l; k < n; k++) + v[k*n+j] += (s * v[k*n+i]); + } + } + for (j = l; j < n; j++) + v[i*n+j] = v[j*n+i] = 0.0; + } + v[i*n+i] = 1.0; + g = rv1[i]; + l = i; + } + + // accumulate the left-hand transformation + for (i = n - 1; i >= 0; i--) + { + l = i + 1; + g = w[i]; + if (i < n - 1) + for (j = l; j < n; j++) + u[i*n+j] = 0.0; + if (g) + { + g = 1.0 / g; + if (i != n - 1) + { + for (j = l; j < n; j++) + { + for (s = 0.0, k = l; k < n; k++) + s += (u[k*n+i] * u[k*n+j]); + f = (s / u[i*n+i]) * g; + for (k = i; k < n; k++) + u[k*n+j] += (f * u[k*n+i]); + } + } + for (j = i; j < n; j++) + u[j*n+i] = (u[j*n+i]*g); + } + else + { + for (j = i; j < n; j++) + u[j*n+i] = 0.0; + } + ++u[i*n+i]; + } + + // diagonalize the bidiagonal form + for (k = n - 1; k >= 0; k--) + { + // loop over singular values + for (its = 0; its < 30; its++) + { + // loop over allowed iterations + flag = 1; + for (l = k; l >= 0; l--) + { + // test for splitting + nm = l - 1; + if (fabs(rv1[l]) + anorm == anorm) + { + flag = 0; + break; + } + if (fabs(w[nm]) + anorm == anorm) + break; + } + if (flag) + { + c = 0.0; + s = 1.0; + for (i = l; i <= k; i++) + { + f = s * rv1[i]; + if (fabs(f) + anorm != anorm) + { + g = w[i]; + h = PYTHAG(f, g); + w[i] = h; + h = 1.0 / h; + c = g * h; + s = (- f * h); + for (j = nm < 0 ? 1 : 0; j < n; j++) + { + y = u[j*n+nm]; + z = u[j*n+i]; + u[j*n+nm] = (y * c + z * s); + u[j*n+i] = (z * c - y * s); + } + } + } + } + z = w[k]; + if (l == k) + { + // convergence + if (z < 0.0) + { + // make singular value nonnegative + w[k] = (-z); + for (j = 0; j < n; j++) + v[j*n+k] = (-v[j*n+k]); + } + break; + } + if (its >= 30) + { + fprintf(stderr, "No convergence after 30,000! iterations \n"); + return 1; + } + + // shift from bottom 2 x 2 minor + x = w[l]; + nm = k - 1; + y = w[nm]; + g = rv1[nm]; + h = rv1[k]; + f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y); + g = PYTHAG(f, 1.0); + f = ((x - z) * (x + z) + h * ((y / (f + SIGNFUNC(g, f))) - h)) / x; + + // next QR transformation + c = s = 1.0; + for (j = l; j <= nm; j++) + { + i = j + 1; + g = rv1[i]; + y = w[i]; + h = s * g; + g = c * g; + z = PYTHAG(f, h); + rv1[j] = z; + c = f / z; + s = h / z; + f = x * c + g * s; + g = g * c - x * s; + h = y * s; + y = y * c; + for (jj = 0; jj < n; jj++) + { + x = v[jj*n+j]; + z = v[jj*n+i]; + v[jj*n+j] = (x * c + z * s); + v[jj*n+i] = (z * c - x * s); + } + z = PYTHAG(f, h); + w[j] = z; + if (z) + { + z = 1.0 / z; + c = f * z; + s = h * z; + } + f = (c * g) + (s * y); + x = (c * y) - (s * g); + for (jj = 0; jj < n; jj++) + { + y = u[jj*n+j]; + z = u[jj*n+i]; + u[jj*n+j] = (y * c + z * s); + u[jj*n+i] = (z * c - y * s); + } + } + rv1[l] = 0.0; + rv1[k] = f; + w[k] = x; + } + } + + for(int i = 0; i < n; i++) + { + INMOST_DATA_REAL_TYPE temp; + for(int j = i + 1; j < n; j++) + { + temp = u[i+n*j]; + u[i+n*j] = u[j+n*i]; + u[j+n*i] = temp; + } + } + for(i = 0; i < n; i++) + { + k = i; + for(j = i+1; j < n; ++j) + if( w[k] < w[j] ) k = j; + INMOST_DATA_REAL_TYPE temp; + if( w[k] > w[i] ) + { + temp = w[k]; + w[k] = w[i]; + w[i] = temp; + for(int j = 0; j < n; ++j) + { + temp = u[k*n+j]; + u[k*n+j] = u[i*n+j]; + u[i*n+j] = temp; + temp = v[j*n+k]; + v[j*n+k] = v[j*n+i]; + v[j*n+i] = temp; + } + } + } + return 0; + } +#endif //USE_LAPACK_SVD +#else //PSEUDOINVERSE + static int solvenxn(INMOST_DATA_REAL_TYPE * A, INMOST_DATA_REAL_TYPE * x, INMOST_DATA_REAL_TYPE * b, int n, int * order) + { + INMOST_DATA_REAL_TYPE temp, max; + int temp2; + for(int i = 0; i < n; i++) order[i] = i; + for(int i = 0; i < n; i++) + { + int maxk = i, maxq = i; + max = fabs(A[maxk*n+maxq]); + //Find best pivot + for(int q = i; q < n; q++) // over columns + { + for(int k = i; k < n; k++) // over rows + { + if( fabs(A[k*n+q]) > max ) + { + max = fabs(A[k*n+q]); + maxk = k; + maxq = q; + } + } + } + //Exchange rows + if( maxk != i ) + { + for(int q = 0; q < n; q++) + { + temp = A[maxk*n+q]; + A[maxk*n+q] = A[i*n+q]; + A[i*n+q] = temp; + } + //exchange rhs + { + temp = b[maxk]; + b[maxk] = b[i]; + b[i] = temp; + } + } + //Exchange columns + if( maxq != i ) + { + for(int k = 0; k < n; k++) + { + temp = A[k*n+maxq]; + A[k*n+maxq] = A[k*n+i]; + A[k*n+i] = temp; + } + //remember order in sol + { + temp2 = order[maxq]; + order[maxq] = order[i]; + order[i] = temp2; + } + } + if( fabs(b[i]/A[i*n+i]) > 1.0e+100 ) + return i+1; + + for(int k = i+1; k < n; k++) + { + A[i*n+k] /= A[i*n+i]; + A[k*n+i] /= A[i*n+i]; + } + for(int k = i+1; k < n; k++) + for(int q = i+1; q < n; q++) + { + A[k*n+q] -= A[k*n+i] * A[i*n+i] * A[i*n+q]; + } + for(int j = i+1; j < n; j++) //iterate over columns of L + { + b[j] -= b[i] * A[j*n+i]; + } + b[i] /= A[i*n+i]; + } + + for(int i = n-1; i >= 0; i--) //iterate over rows of U + for(int j = i+1; j < n; j++) + { + b[i] -= b[j] * A[i*n+j]; + } + for(int i = 0; i < n; i++) + x[order[i]] = b[i]; + + return 0; + } +#endif //PSEUDOINVERSE + class BCGSL_solver : public IterativeMethod + { + INMOST_DATA_REAL_TYPE length; + INMOST_DATA_REAL_TYPE rtol, atol, divtol, last_resid; + INMOST_DATA_ENUM_TYPE iters, maxits, l, last_it; + INMOST_DATA_REAL_TYPE resid; + INMOST_DATA_REAL_TYPE * tau, * sigma, * gamma, *theta1, * theta2, * theta3; + Sparse::Vector r_tilde, x0, t, * u, * r; + Sparse::Matrix * Alink; + Method * prec; + std::string reason; + Solver::OrderInfo * info; + bool init; + public: + INMOST_DATA_ENUM_TYPE GetIterations() {return last_it;} + INMOST_DATA_REAL_TYPE GetResidual() {return last_resid;} + INMOST_DATA_REAL_TYPE & RealParameter(std::string name) + { + if (name[0] == ':') + { + if (prec != NULL) return prec->RealParameter(name.substr(1, name.size() - 1)); + } + if (name == "rtol") return rtol; + else if (name == "atol") return atol; + else if (name == "divtol") return divtol; + else if (prec != NULL) return prec->RealParameter(name); + throw - 1; + } + INMOST_DATA_ENUM_TYPE & EnumParameter(std::string name) + { + if (name[0] == ':') + { + if (prec != NULL) return prec->EnumParameter(name.substr(1, name.size() - 1)); + } + if (name == "maxits") return maxits; + else if (name == "levels") + { + if( init ) throw - 1; //solver was already initialized, value should not be changed + return l; + } + else if (prec != NULL) return prec->EnumParameter(name); + throw - 1; + } + BCGSL_solver(Method * prec, Solver::OrderInfo & info) + :rtol(1e-8), atol(1e-9), divtol(1e+40), maxits(1500),l(2),prec(prec),info(&info) + { + Alink = NULL; + init = false; + } + bool Initialize() + { + if (isInitialized()) Finalize(); + if (prec != NULL && !prec->isInitialized()) prec->Initialize(); + info->PrepareVector(r_tilde); + info->PrepareVector(x0); + info->PrepareVector(t); + tau = new INMOST_DATA_REAL_TYPE[l * 3 + (l+1)*(l+1) + (l+1)*2]; + sigma = tau + (l+1)*(l+1); + gamma = sigma + l+1; + theta1 = gamma + l+1; + theta2 = theta1 + l; + theta3 = theta2 + l; + u = new Sparse::Vector[l * 2 + 2]; + r = u + l + 1; + for (INMOST_DATA_ENUM_TYPE k = 0; k < l + 1; k++) + { + info->PrepareVector(r[k]); + info->PrepareVector(u[k]); + } + init = true; + return true; + } + bool isInitialized() { return init && (prec == NULL || prec->isInitialized()); } + bool Finalize() + { + if (isInitialized()) + { + if (!prec->isFinalized()) prec->Finalize(); + delete[] u; + delete[] tau; + init = false; + } + return true; + } + bool isFinalized() { return !init && (prec == NULL || prec->isFinalized()); } + void Copy(const Method * other) + { + const BCGSL_solver * b = dynamic_cast(other); + assert(b != NULL); + rtol = b->rtol; + atol = b->atol; + divtol = b->divtol; + last_resid = b->last_resid; + iters = b->iters; + maxits = b->maxits; + l = b->l; + last_it = b->last_it; + resid = b->resid; + Alink = b->Alink; + info = b->info; + if (init) Finalize(); + if (b->prec != NULL) + { + if (prec == NULL) prec = b->prec->Duplicate(); + else prec->Copy(b->prec); + } + if (b->init) Initialize(); + } + BCGSL_solver(const BCGSL_solver & other) :IterativeMethod(other) + { + Copy(&other); + } + BCGSL_solver & operator =(BCGSL_solver const & other) + { + Copy(&other); + return *this; + } + ~BCGSL_solver() + { + if (!isFinalized()) Finalize(); + if (prec != NULL) delete prec; + } + void ApplyOperator(Sparse::Vector & Input, Sparse::Vector & Output) + { + if (prec != NULL) //right preconditioning here! for left preconditioner have to reverse order + { + prec->Solve(Input, t); + info->Update(t); + Alink->MatVec(1.0,t,0,Output); + info->Update(Output); + } + else + { + Alink->MatVec(1.0,Input,0,Output); + info->Update(Output); + } + } + bool Solve(Sparse::Vector & RHS, Sparse::Vector & SOL) + { + assert(isInitialized()); + INMOST_DATA_ENUM_TYPE vbeg,vend, vlocbeg, vlocend; + INMOST_DATA_INTEGER_TYPE ivbeg, ivend, ivlocbeg, ivlocend; + INMOST_DATA_REAL_TYPE rho0 = 1, rho1 = 1, alpha = 0, beta = 0, omega = 1, eta = 0; + INMOST_DATA_REAL_TYPE resid0, resid, rhs_norm, tau_sum = 0, sigma_sum = 0,r_tilde_norm = 0;//, temp[2]; + iters = 0; + info->PrepareVector(SOL); + info->PrepareVector(RHS); + info->Update(SOL); + info->Update(RHS); + if( prec != NULL ) prec->ReplaceSOL(SOL); + if( prec != NULL ) prec->ReplaceRHS(RHS); + info->GetLocalRegion(info->GetRank(),vlocbeg,vlocend); + info->GetVectorRegion(vbeg,vend); + ivbeg = vbeg; + ivend = vend; + ivlocbeg = vlocbeg; + ivlocend = vlocend; + //info->ScalarProd(RHS,RHS,vlocbeg,vlocend,rhs_norm); + rhs_norm = 1; + //r[0] = b + std::copy(RHS.Begin(),RHS.End(),r[0].Begin()); + { + // r[0] = r[0] - A x + Alink->MatVec(-1,SOL,1,r[0]); //global multiplication, r probably needs an update + info->Update(r[0]); // r is good + std::copy(SOL.Begin(),SOL.End(),x0.Begin()); //x0 = x + std::fill(SOL.Begin(),SOL.End(),0.0); //x = 0 + } + std::copy(r[0].Begin(),r[0].End(),r_tilde.Begin()); // r_tilde = r[0] + std::fill(u[0].Begin(),u[0].End(),0); // u[0] = 0 + resid = 0; +#if defined(USE_OMP) +#pragma omp parallel for reduction(+:resid) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + resid += r[0][k]*r[0][k]; + info->Integrate(&resid,1); + //info->ScalarProd(r[0],r[0],vlocbeg,vlocend,resid); //resid = dot(r[0],r[0]) + last_resid = resid = resid0 = sqrt(resid/rhs_norm); //resid = sqrt(dot(r[0],r[0]) +#if defined(USE_OMP) +#pragma omp parallel for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivbeg; k < ivend; ++k) // r_tilde = r[0] / dot(r[0],r[0]) + r_tilde[k] /= resid; + last_it = 0; +#if defined(REPORT_RESIDUAL) + if( info->GetRank() == 0 ) + { + //std::cout << "iter " << last_it << " residual " << resid << std::endl; + //std::cout << "iter " << last_it << " resid " << resid << "\r"; + //printf("iter %3d resid %12g | %12g relative %12g | %12g\r", last_it, resid, atol, resid / resid0, rtol); + printf("iter %3d resid %12g | %g\r", last_it, resid, atol); + fflush(stdout); + } +#endif + + bool halt = false; + if( last_resid < atol || last_resid < rtol*resid0 ) + { + reason = "initial solution satisfy tolerances"; + halt = true; + } + +#if defined(USE_OMP) +#pragma omp parallel +#endif + { + INMOST_DATA_ENUM_TYPE i = 0; + while( !halt ) + { + +#if defined(USE_OMP) +#pragma omp single +#endif + { + rho0 = -omega*rho0; + } + + + for(INMOST_DATA_ENUM_TYPE j = 0; j < l; j++) + { + if( false ) + { +perturbate: +#if defined(PERTURBATE_RTILDE) + //std::cout << "Rescue solver by perturbing orthogonal direction!" << std::endl; + //Compute length of the vector +#if defined(USE_OMP) +#pragma omp single +#endif + { + length = static_cast(ivlocend-ivlocbeg); + r_tilde_norm = 0.0; + } + info->Integrate(&length,1); + //perform perturbation (note that rand() with openmp may give identical sequences of random values +#if defined(USE_OMP) +#pragma omp for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + { + INMOST_DATA_REAL_TYPE unit = 2*static_cast(rand())/static_cast(RAND_MAX)-1.0; + r_tilde[k] += unit/length; + } + //compute norm for orthogonal vector +#if defined(USE_OMP) +#pragma omp for reduction(+:r_tilde_norm) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + r_tilde_norm += r_tilde[k]*r_tilde[k]; +#if defined(USE_OMP) +#pragma omp single +#endif + { + r_tilde_norm = sqrt(r_tilde_norm); + } + info->Integrate(&r_tilde_norm,1); + //normalize orthogonal vector to unity +#if defined(USE_OMP) +#pragma omp for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + r_tilde[k] /= r_tilde_norm; + //Recompute rho1 +#else + reason = "r_tilde perturbation algorithm is disabled"; + halt = true; + break; +#endif + } +#if defined(USE_OMP) +#pragma omp single +#endif + rho1 = 0; +#if defined(USE_OMP) +#pragma omp for reduction(+:rho1) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + rho1+= r[j][k]*r_tilde[k]; + info->Integrate(&rho1,1); + if( fabs(rho1) < 1.0e-50 ) + { + //std::cout << "Asking to perturbate r_tilde since rho1 is too small " << rho1 << std::endl; + goto perturbate; + } + //info->ScalarProd(r[j],r_tilde,vlocbeg,vlocend,rho1); // rho1 = dot(r[j],r_tilde) +#if defined(USE_OMP) +#pragma omp single +#endif + { + beta = alpha * (rho1/rho0); + } + + if( fabs(beta) > 1.0e+100 ) + { + //std::cout << "alpha " << alpha << " rho1 " << rho1 << " rho0 " << rho0 << " beta " << beta << std::endl; +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(1) is too large"; + halt = true; + } + break; + } + + if( beta != beta ) + { + //std::cout << "alpha " << alpha << " rho1 " << rho1 << " rho0 " << rho0 << " beta " << beta << std::endl; +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(1) is NaN"; + halt = true; + } + break; + } +#if defined(USE_OMP) +#pragma omp single +#endif + { + rho0 = rho1; + } + for(INMOST_DATA_ENUM_TYPE m = 0; m < j+1; m++) + { +#if defined(USE_OMP) +#pragma omp for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivbeg; k < ivend; ++k) + u[m][k] = r[m][k] - beta*u[m][k]; + } + + + ApplyOperator(u[j],u[j+1]); // u[j+1] = A*R*u[j] +#if defined(USE_OMP) +#pragma omp single +#endif + eta = 0; +#if defined(USE_OMP) +#pragma omp for reduction(+:eta) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + eta += u[j+1][k]*r_tilde[k]; + info->Integrate(&eta,1); + //info->ScalarProd(u[j+1],r_tilde,vlocbeg,vlocend,eta); //eta = dot(u[j+1],r_tilde) + + if( fabs(eta) < 1.0e-50 ) + { + //std::cout << "Asking to perturbate r_tilde since eta is too small " << eta << std::endl; + goto perturbate; + } + +#if defined(USE_OMP) +#pragma omp single +#endif + alpha = rho0 / eta; + + if( fabs(alpha) > 1.0e+100 ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(2) is too large"; + halt = true; + } + break; + } + if( alpha != alpha ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(2) is NaN"; + halt = true; + } + break; + } + +#if defined(USE_OMP) +#pragma omp for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivbeg; k < ivend; ++k) + SOL[k] += alpha*u[0][k]; + + for(INMOST_DATA_ENUM_TYPE m = 0; m < j+1; m++) + { +#if defined(USE_OMP) +#pragma omp for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivbeg; k < ivend; ++k) //r[i] = r[i] - alpha * u[i+1] + r[m][k] -= alpha*u[m+1][k]; + } + + +#if defined(USE_OMP) +#pragma omp single +#endif + resid = 0; +#if defined(USE_OMP) +#pragma omp for reduction(+:resid) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + resid += r[0][k]*r[0][k]; + info->Integrate(&resid,1); + //info->ScalarProd(r[0],r[0],vlocbeg,vlocend,resid); // resid = dot(r[j],r[j]) +#if defined(USE_OMP) +#pragma omp single +#endif + { + resid = sqrt(resid/rhs_norm); // resid = sqrt(dot(r[j],r[j])) + last_it++; + } + + if( resid < atol || resid < rtol*resid0 ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + reason = "early exit in bi-cg block"; + last_resid = resid; + halt = true; + break; + } + ApplyOperator(r[j],r[j+1]); // r[j+1] = A*R*r[j] + } + + if( halt ) break; + INMOST_DATA_ENUM_TYPE size = l; +#if defined(CONVEX_COMBINATION) + size = l+1; +#endif + // Penalization for convex combination for update below + for(INMOST_DATA_ENUM_TYPE j = 1; j < l+1; j++) + { + for(INMOST_DATA_ENUM_TYPE m = 1; m < j+1; m++) + { +#if defined(USE_OMP) +#pragma omp single +#endif + tau_sum = 0.0; +#if defined(USE_OMP) +#pragma omp for reduction(+:tau_sum) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + tau_sum += r[j][k]*r[m][k]; + + if( fabs(tau_sum) > 1.0e+100 ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(tau) is too large"; + halt = true; + } + } + if( tau_sum != tau_sum ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(tau) is NaN"; + halt = true; + } + } +#if defined(USE_OMP) +#pragma omp single +#endif + { + tau[(j-1) + (m-1)*size] = tau[(m-1) + (j-1)*size] = tau_sum; + } + } +#if defined(USE_OMP) +#pragma omp single +#endif + sigma_sum = 0; +#if defined(USE_OMP) +#pragma omp for reduction(+:sigma_sum) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + sigma_sum += r[0][k]*r[j][k]; + + if( fabs(sigma_sum) > 1.0e+100 ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(sigma) is too large"; + halt = true; + } + } + if( sigma_sum != sigma_sum ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(sigma) is NaN"; + halt = true; + } + } +#if defined(USE_OMP) +#pragma omp single +#endif + { + sigma[j-1] = sigma_sum; + } + } + + if( halt ) break; + +#if defined(CONVEX_COMBINATION) +#if defined(USE_OMP) +#pragma omp single +#endif + { + INMOST_DATA_REAL_TYPE lagrangian = 0.0; + for(INMOST_DATA_ENUM_TYPE j = 0; j < l; j++) lagrangian += tau[j+size*j]; + sigma[l] = lagrangian; + tau[(l+1)*(l+1)-1] = 0.0; + for(INMOST_DATA_ENUM_TYPE j = 0; j < l; j++) + { + tau[l + j*(l+1)] = -lagrangian; + tau[l*(l+1)+j] = lagrangian; + } + } +#endif + info->Integrate(tau,(l+2)*(l+1)); //sigma is updated with tau + //info->Integrate(tau,size*size); + //info->Integrate(sigma,size); + +#if defined(USE_OMP) +#pragma omp single +#endif +#if defined(PSEUDOINVERSE) + { + int dgesvd_info = 0; +#if defined(USE_LAPACK_SVD) + char c = 'A'; + INMOST_DATA_REAL_TYPE U[128*128], V[128*128], w[128]; + INMOST_DATA_REAL_TYPE work[5*128]; + int lwork = 5*128; + int n = static_cast(size); + dgesvd_(&c,&c,&n,&n,tau,&n,w,U,&n,V,&n,work,&lwork,&dgesvd_info); +#else + /* + char c = 'A'; + INMOST_DATA_REAL_TYPE U2[128*128], V2[128*128], w2[128], tau2[128*128]; + INMOST_DATA_REAL_TYPE work[5*128]; + int lwork = 5*128; + int n = l; + memcpy(tau2,tau,sizeof(INMOST_DATA_REAL_TYPE)*l*l); + dgesvd_(&c,&c,&n,&n,tau2,&n,w2,U2,&n,V2,&n,work,&lwork,&dgesvd_info); + printf("dgesvd\n"); + printf("w\n"); + for(int q = 0; q < l; ++q) printf("%g ",w2[q]); + printf("\nU\n"); + for(int q = 0; q < l*l; ++q) + { + printf("%g ",U2[q]); + if( (q+1)%l == 0 ) printf("\n"); + } + printf("V\n"); + for(int q = 0; q < l*l; ++q) + { + printf("%g ",V2[q]); + if( (q+1)%l == 0 ) printf("\n"); + } + */ + INMOST_DATA_REAL_TYPE U[128*128], V[128*128], w[128]; + dgesvd_info = svdnxn(tau,U,w,V,size); + //for(INMOST_DATA_ENUM_TYPE j = 0; j < l; j++) w[j] = S[j*l+j]; + /* + printf("svdnxn\n"); + printf("w\n"); + for(int q = 0; q < l; ++q) printf("%g ",w[q]); + printf("\nU\n"); + for(int q = 0; q < l*l; ++q) + { + printf("%g ",U[q]); + if( (q+1)%l == 0 ) printf("\n"); + } + printf("V\n"); + for(int q = 0; q < l*l; ++q) + { + printf("%g ",V[q]); + if( (q+1)%l == 0 ) printf("\n"); + } + */ +#endif + /* + printf("w "); + for(INMOST_DATA_ENUM_TYPE j = 0; j < l; j++) printf("%20g ",w[j]); + printf("\n"); + + printf("U\n"); + for(INMOST_DATA_ENUM_TYPE j = 0; j < l*l; j++) + { + printf("%20g ",U[j]); + if( (j+1) % l == 0 ) printf("\n"); + } + printf("\n"); + + printf("VT\n"); + for(INMOST_DATA_ENUM_TYPE j = 0; j < l*l; j++) + { + printf("%20g ",V[j]); + if( (j+1) % l == 0 ) printf("\n"); + } + printf("\n"); + */ + if( dgesvd_info != 0 ) + { + printf("(%s:%d) dgesvd %d\n",__FILE__,__LINE__,dgesvd_info); + exit(-1); + } + + INMOST_DATA_REAL_TYPE maxw = w[0], tol; + for(INMOST_DATA_ENUM_TYPE j = 1; j < size; j++) if(w[j]>maxw) maxw = w[j]; + tol = size*maxw*1.0e-14; + memset(gamma,0,sizeof(INMOST_DATA_REAL_TYPE)*size); + for(INMOST_DATA_ENUM_TYPE j = 0; j < size; j++) + { + if( w[j] > tol ) + { + INMOST_DATA_REAL_TYPE sum = 0; + for(INMOST_DATA_ENUM_TYPE k = 0; k < size; ++k) + sum += sigma[k]*U[j*size+k]; + for(INMOST_DATA_ENUM_TYPE k = 0; k < size; ++k) + gamma[k] += sum/w[j]*V[k*size+j]; + } + } + } + + //svdnxn(tau,U,S,V,l); + //INMOST_DATA_REAL_TYPE inv_tau[64]; + //pseudoinverse(tau,inv_tau,l); + //matmul(inv_tau,sigma,gamma,l,l,1); +#else + { + int order[128]; + int row = solvenxn(tau,gamma,sigma,size,order); + /* + double sum = 0.0; + for(int j = 0; j < l; ++j) + { + sum += gamma[j]; + std::cout << gamma[j] << " "; + } + std::cout << "sum: " << sum; + //std::cout << " lagrangian: " << gamma[l]; + std::cout << std::endl; + */ + if( row != 0 ) + { + std::cout << "breakdown on row " << row << std::endl; + reason = "breakdown in matrix inversion in polynomial part"; + break; + } + } +#endif +#if defined(USE_OMP) +#pragma omp single +#endif + omega = gamma[l-1]; + if( fabs(omega) > 1.0e+100 ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(3) is too large"; + halt = true; + } + break; + } + if( omega != omega ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(3) is NaN"; + halt = true; + } + break; + } + for(INMOST_DATA_ENUM_TYPE j = 1; j < l+1; ++j) + { +#if defined(USE_OMP) +#pragma omp for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivbeg; k < ivend; ++k) + { + u[0][k] -= gamma[j-1]*u[j][k]; + SOL[k] += gamma[j-1]*r[j-1][k]; + r[0][k] -= gamma[j-1]*r[j][k]; + } + } + + + /* + for(INMOST_DATA_ENUM_TYPE j = 1; j < l+1; j++) + { + for(INMOST_DATA_ENUM_TYPE i = 1; i < j; i++) + { + tau[i-1 + (j-1)*l] = 0; + for(INMOST_DATA_ENUM_TYPE k = vlocbeg; k < vlocend; ++k) + tau[i-1 + (j-1)*l] += r[j][k]*r[i][k]; + info->Integrate(&tau[i-1 + (j-1)*l],1); + tau[i-1 + (j-1)*l] /= sigma[i-1]; + for(INMOST_DATA_ENUM_TYPE k = vbeg; k < vend; ++k) + r[j][k] -= tau[i-1 + (j-1)*l]*r[i][k]; + } + INMOST_DATA_REAL_TYPE temp[2] = {0,0}; + for(INMOST_DATA_ENUM_TYPE k = vlocbeg; k < vlocend; ++k) + { + temp[0] += r[j][k]*r[j][k]; + temp[1] += r[0][k]*r[j][k]; + } + info->Integrate(temp,2); + sigma[j-1] = temp[0];//+1.0e-35; //REVIEW + theta2[j-1] = temp[1]/sigma[j-1]; + } + omega = theta1[l-1] = theta2[l-1]; + for(INMOST_DATA_ENUM_TYPE j = l-1; j > 0; j--) + { + eta = 0; + for(INMOST_DATA_ENUM_TYPE i = j+1; i < l+1; i++) + eta += tau[j-1 + (i-1)*l] * theta1[i-1]; + theta1[j-1] = theta2[j-1] - eta; + } + for(INMOST_DATA_ENUM_TYPE j = 1; j < l; j++) + { + eta = 0; + for(INMOST_DATA_ENUM_TYPE i = j+1; i < l; i++) + eta += tau[j-1 + (i-1)*l] * theta1[i]; + theta3[j-1] = theta1[j] + eta; + } + for(INMOST_DATA_ENUM_TYPE k = vbeg; k < vend; ++k) + { + SOL[k] += theta1[0]*r[0][k]; + r[0][k] -= theta2[l-1]*r[l][k]; + u[0][k] -= theta1[l-1]*u[l][k]; + } + for(INMOST_DATA_ENUM_TYPE j = 1; j < l; j++) + { + for(INMOST_DATA_ENUM_TYPE k = vbeg; k < vend; ++k) + { + u[0][k] -= theta1[j-1]*u[j][k]; + SOL[k] += theta3[j-1]*r[j][k]; + r[0][k] -= theta2[j-1]*r[j][k]; + } + } + */ + //last_it = l+1; + { +#if defined(USE_OMP) +#pragma omp single +#endif + resid = 0; +#if defined(USE_OMP) +#pragma omp for reduction(+:resid) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + resid += r[0][k]*r[0][k]; + info->Integrate(&resid,1); + //info->ScalarProd(r[0],r[0],vlocbeg,vlocend,resid); +#if defined(USE_OMP) +#pragma omp single +#endif + resid = sqrt(resid/rhs_norm); + } + +#if defined(REPORT_RESIDUAL) + if( info->GetRank() == 0 ) + { + //std::cout << "iter " << last_it << " residual " << resid << " time " << tt << " matvec " << ts*0.5/l << " precond " << tp*0.5/l << std::endl; + //std::cout << "iter " << last_it << " resid " << resid << "\r"; + //printf("iter %3d resid %12g | %12g relative %12g | %12g\r", last_it, resid, atol, resid / resid0, rtol); +#if defined(USE_OMP) +#pragma omp single +#endif + { + printf("iter %3d resid %12g | %g\r", last_it, resid, atol); + fflush(stdout); + } + } +#endif +#if defined(USE_OMP) +#pragma omp single +#endif + last_resid = resid; + if( resid != resid ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + reason = "residual is NAN"; + break; + } + if( resid < atol ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + reason = "converged due to absolute tolerance"; + break; + } + if( resid < rtol*resid0 ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + reason = "converged due to relative tolerance"; + break; + } + if( resid > divtol ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + reason = "diverged due to divergence tolerance"; + break; + } + if( i == maxits ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + reason = "reached maximum iteration number"; + break; + } + i++; + } + } + if (prec != NULL) + { + prec->Solve(SOL, r_tilde); //undo right preconditioner + std::copy(r_tilde.Begin(), r_tilde.End(), SOL.Begin()); + } +#if defined(USE_OMP) +#pragma omp parallel for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) //undo shift + SOL[k] += x0[k]; + //info->RestoreMatrix(A); + info->RestoreVector(SOL); + info->RestoreVector(RHS); + if( last_resid < atol || last_resid < rtol*resid0 ) return true; + return false; + } + bool ReplaceMAT(Sparse::Matrix & A) { if (isInitialized()) Finalize(); if (prec != NULL) prec->ReplaceMAT(A); Alink = &A; return true; } + bool ReplaceRHS(Sparse::Vector & RHS) { (void) RHS; return true; } + bool ReplaceSOL(Sparse::Vector & SOL) { (void) SOL; return true; } + Method * Duplicate() { return new BCGSL_solver(*this);} + std::string GetReason() {return reason;} + }; + + + class BCGS_solver : public IterativeMethod + { + INMOST_DATA_REAL_TYPE rtol, atol, divtol, last_resid; + INMOST_DATA_ENUM_TYPE iters, maxits, last_it; + INMOST_DATA_REAL_TYPE resid; + Sparse::Vector r0, p, y, s, t, z, r, v; + Sparse::Matrix * Alink; + Method * prec; + Solver::OrderInfo * info; + bool init; + std::string reason; + public: + INMOST_DATA_ENUM_TYPE GetIterations() {return last_it;} + INMOST_DATA_REAL_TYPE GetResidual() {return last_resid;} + INMOST_DATA_REAL_TYPE & RealParameter(std::string name) + { + if (name[0] == ':') + { + if (prec != NULL) return prec->RealParameter(name.substr(1, name.size() - 1)); + } + if (name == "rtol") return rtol; + else if (name == "atol") return atol; + else if (name == "divtol") return divtol; + else if( prec != NULL ) return prec->RealParameter(name); + throw - 1; + } + INMOST_DATA_ENUM_TYPE & EnumParameter(std::string name) + { + if (name[0] == ':') + { + if (prec != NULL) return prec->EnumParameter(name.substr(1, name.size() - 1)); + } + if (name == "maxits") return maxits; + else if (prec != NULL) return prec->EnumParameter(name); + throw - 1; + } + BCGS_solver(Method * prec, Solver::OrderInfo & info) + :rtol(1e-8), atol(1e-11), divtol(1e+40), iters(0), maxits(1500),prec(prec),info(&info) + { + init = false; + } + bool Initialize() + { + assert(Alink != NULL); + if (isInitialized()) Finalize(); + if (prec != NULL && !prec->isInitialized()) prec->Initialize(); + info->PrepareVector(r); + info->PrepareVector(v); + info->PrepareVector(p); + info->PrepareVector(y); + info->PrepareVector(s); + info->PrepareVector(t); + info->PrepareVector(z); + info->PrepareVector(r0); + init = true; + return true; + } + bool isInitialized() { return init && (prec == NULL || prec->isInitialized()); } + bool Finalize() + { + if (prec != NULL && !prec->isFinalized()) prec->Finalize(); + init = false; + return true; + } + bool isFinalized() { return !init && (prec == NULL || prec->isFinalized()); } + void Copy(const Method * other) + { + const BCGS_solver * b = dynamic_cast(other); + assert(b != NULL); + info = b->info; + rtol = b->rtol; + atol = b->atol; + divtol = b->divtol; + maxits = b->maxits; + last_resid = b->last_resid; + iters = b->iters; + last_it = b->last_it; + resid = b->resid; + Alink = b->Alink; + if (b->prec != NULL) + { + if (prec == NULL) prec = b->prec->Duplicate(); + else prec->Copy(b->prec); + } + if (b->init) Initialize(); + } + BCGS_solver(const BCGS_solver & other) : IterativeMethod(other) + { + Copy(&other); + } + BCGS_solver & operator =(BCGS_solver const & other) + { + Copy(&other); + return *this; + } + ~BCGS_solver() + { + if (!isFinalized()) Finalize(); + if (prec != NULL) delete prec; + } + bool Solve(Sparse::Vector & RHS, Sparse::Vector & SOL) + { + assert(isInitialized()); + INMOST_DATA_REAL_TYPE tempa = 0.0, tempb=0.0, r0_norm = 0, length; + INMOST_DATA_ENUM_TYPE vbeg,vend, vlocbeg, vlocend; + INMOST_DATA_INTEGER_TYPE ivbeg,ivend, ivlocbeg, ivlocend; + INMOST_DATA_REAL_TYPE rho = 1, rho1 = 0, alpha = 1, beta = 0, omega = 1; + INMOST_DATA_REAL_TYPE resid0, resid, temp[2] = {0,0}; + iters = 0; + info->PrepareVector(SOL); + info->PrepareVector(RHS); + info->Update(SOL); + info->Update(RHS); + if (prec != NULL)prec->ReplaceSOL(SOL); + if (prec != NULL)prec->ReplaceRHS(RHS); + info->GetLocalRegion(info->GetRank(),vlocbeg,vlocend); + info->GetVectorRegion(vbeg,vend); + ivbeg = vbeg; + ivend = vend; + ivlocbeg = vlocbeg; + ivlocend = vlocend; + + std::copy(RHS.Begin(),RHS.End(),r.Begin()); + { + Alink->MatVec(-1,SOL,1,r); //global multiplication, r probably needs an update + info->Update(r); // r is good + } + std::copy(r.Begin(),r.End(),r0.Begin()); + std::fill(v.Begin(),v.End(),0.0); + std::fill(p.Begin(),p.End(),0.0); + { + resid = 0; +#if defined(USE_OMP) +#pragma omp parallel for reduction(+:resid) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; k++) + resid += r0[k]*r0[k]; + info->Integrate(&resid,1); + } + last_resid = resid = resid0 = sqrt(resid); +#if defined(USE_OMP) +#pragma omp parallel for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivbeg; k < ivend; ++k) // r_tilde = r[0] / dot(r[0],r[0]) + r0[k] /= resid; + last_it = 0; +#if defined(REPORT_RESIDUAL) + if( info->GetRank() == 0 ) + { + //std::cout << "iter " << last_it << " residual " << resid << std::endl; + //std::cout << "iter " << last_it << " resid " << resid << "\r"; + //printf("iter %3d resid %12g | %12g relative %12g | %12g\r",last_it,resid,atol,resid/resid0,rtol); + printf("iter %3d resid %12g | %g\r", last_it, resid, atol); + fflush(stdout); + } +#endif + + bool halt = false; + if( last_resid < atol || last_resid < rtol*resid0 ) + { + reason = "initial solution satisfy tolerances"; + halt = true; + } + +#if defined(USE_OMP) +#pragma omp parallel +#endif + { + INMOST_DATA_ENUM_TYPE i = 0; + while( !halt ) + { + + if( false ) + { +perturbate: +#if defined(PERTURBATE_RTILDE) + //std::cout << "Rescue solver by perturbing orthogonal direction!" << std::endl; + //Compute length of the vector +#if defined(USE_OMP) +#pragma omp single +#endif + { + length = static_cast(ivlocend-ivlocbeg); + r0_norm = 0.0; + } + info->Integrate(&length,1); + //perform perturbation (note that rand() with openmp may give identical sequences of random values +#if defined(USE_OMP) +#pragma omp for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + { + INMOST_DATA_REAL_TYPE unit = 2*static_cast(rand())/static_cast(RAND_MAX)-1.0; + r0[k] += unit/length; + } + //compute norm for orthogonal vector +#if defined(USE_OMP) +#pragma omp for reduction(+:r0_norm) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + r0_norm += r0[k]*r0[k]; +#if defined(USE_OMP) +#pragma omp single +#endif + { + r0_norm = sqrt(r0_norm); + } + info->Integrate(&r0_norm,1); + //normalize orthogonal vector to unity +#if defined(USE_OMP) +#pragma omp for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + r0[k] /= r0_norm; + //Recompute rho1 +#else + reason = "r_tilde perturbation algorithm is disabled"; + halt = true; + break; +#endif + } + + /* + if( fabs(rho) < 1.0e-31 ) + { + std::cout << "rho " << rho << " alpha " << alpha << " omega " << omega << " beta " << 1.0 /rho * alpha / omega << std::endl; + reason = "denominator(1) is zero"; + break; + } + if( fabs(omega) < 1.0e-31 ) + { + std::cout << "rho " << rho << " alpha " << alpha << " omega " << omega << " beta " << 1.0 /rho * alpha / omega << std::endl; + reason = "denominator(2) is zero"; + break; + } + */ + +#if defined(USE_OMP) +#pragma omp single +#endif + { + beta = 1.0 / rho * alpha / omega; + rho1 = 0; + } + +#if defined(USE_OMP) +#pragma omp for reduction(+:rho1) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + rho1 += r0[k]*r[k]; + + info->Integrate(&rho1,1); + + if( fabs(rho1) < 1.0e-50 ) + { + //std::cout << "Asking to perturbate r_tilde since rho1 is too small " << rho1 << std::endl; + goto perturbate; + } + +#if defined(USE_OMP) +#pragma omp single +#endif + { + beta *= rho1; + rho = rho1; + } + + if( fabs(beta) > 1.0e+100 ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(1) is too large"; + halt = true; + } + continue; + } + + if( beta != beta ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(1) is NaN"; + halt = true; + } + continue; + } + + +#if defined(USE_OMP) +#pragma omp for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivbeg; k < ivend; ++k) + p[k] = r[k] + beta*(p[k] - omega*v[k]); //global indexes r, p, v + + + + if (prec != NULL) + { + prec->Solve(p, y); + info->Update(y); + Alink->MatVec(1,y,0,v); // global multiplication, y should be updated, v probably needs an update + info->Update(v); + } + else + { + Alink->MatVec(1,p,0,v); // global multiplication, y should be updated, v probably needs an update + info->Update(v); + } + + +#if defined(USE_OMP) +#pragma omp single +#endif + { + alpha = 0; + } +#if defined(USE_OMP) +#pragma omp for reduction(+:alpha) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + alpha += r0[k]*v[k]; + info->Integrate(&alpha,1); + //info->ScalarProd(r0,v,ivlocbeg,ivlocend,alpha); +#if defined(USE_OMP) +#pragma omp single +#endif + { + //if( alpha == 0 && rho == 0 ) + // alpha = 0; + //else + alpha = rho / alpha; //local indexes, r0, v + } + + if( fabs(alpha) > 1.0e+100 ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(2) is too large"; + halt = true; + } + continue; + } + + if( alpha != alpha ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(2) is NaN"; + halt = true; + } + continue; + } + +#if defined(USE_OMP) +#pragma omp for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivbeg; k < ivend; ++k) + s[k] = r[k] - alpha * v[k]; //global indexes r, v + + + + if (prec != NULL) + { + prec->Solve(s, z); + info->Update(z); + Alink->MatVec(1.0,z,0,t); // global multiplication, z should be updated, t probably needs an update + info->Update(t); + } + else + { + Alink->MatVec(1.0,s,0,t); // global multiplication, z should be updated, t probably needs an update + info->Update(t); + } + + + +#if defined(USE_OMP) +#pragma omp single +#endif + { + tempa = 0.0; //can be negative + tempb = 1.0e-100; //tempb is positive since squared + } +#if defined(USE_OMP) +#pragma omp for reduction(+:tempa,tempb) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; k++) + { + tempa += t[k]*s[k]; + tempb += t[k]*t[k]; + } +#if defined(USE_OMP) +#pragma omp single +#endif + { + temp[0] = tempa; + temp[1] = tempb; + } + info->Integrate(temp,2); + + //omega = temp[0] / (temp[1] + (temp[1] < 0.0 ? -1.0e-10 : 1.0e-10)); //local indexes t, s +#if defined(USE_OMP) +#pragma omp single +#endif + { + //if( temp[0] == 0 && temp[1] == 0 ) + // omega = 0; + //else + omega = temp[0] / temp[1]; + } + + if( fabs(omega) > 1.0e+100 ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(3) is too large"; + halt = true; + } + continue; + } + + if( omega != omega ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "multiplier(3) is NaN"; + halt = true; + } + continue; + } + + +#if defined(USE_OMP) +#pragma omp for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivbeg; k < ivend; ++k) + SOL[k] += alpha * y[k] + omega * z[k]; // global indexes SOL, y, z + + +#if defined(USE_OMP) +#pragma omp for +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivbeg; k < ivend; ++k) + r[k] = s[k] - omega * t[k]; // global indexes r, s, t + + //info->ScalarProd(r,r,ivlocbeg,ivlocend,resid); +#if defined(USE_OMP) +#pragma omp single +#endif + { + last_it++; + resid = 0; + } +#if defined(USE_OMP) +#pragma omp for reduction(+:resid) +#endif + for(INMOST_DATA_INTEGER_TYPE k = ivlocbeg; k < ivlocend; ++k) + resid += r[k]*r[k]; + info->Integrate(&resid,1); +#if defined(USE_OMP) +#pragma omp single +#endif + { + resid = sqrt(resid); + } +#if defined(REPORT_RESIDUAL) + if( info->GetRank() == 0 ) + { + //std::cout << "iter " << last_it << " residual " << resid << " time " << tt << " matvec " << ts*0.5 << " precond " << tp*0.5 << std::endl; + //std::cout << "iter " << last_it << " resid " << resid << "\r"; + //printf("iter %3d resid %12g | %12g relative %12g | %12g\r", last_it, resid, atol, resid / resid0, rtol); +#if defined(USE_OMP) +#pragma omp single +#endif + { + printf("iter %3d resid %12g | %g\r", last_it, resid, atol); + //printf("iter %3d resid %12g | %g rho %e beta %e alpha %e omega %e\n", last_it, resid, atol,rho,beta,alpha,omega); + fflush(stdout); + } + } +#endif +#if defined(USE_OMP) +#pragma omp single +#endif + { + last_resid = resid; + } + if( resid != resid ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "residual is NAN"; + halt = true; + } + } + if( resid > divtol ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "diverged due to divergence tolerance"; + halt = true; + } + } + if( resid < atol ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "converged due to absolute tolerance"; + halt = true; + } + } + if( resid < rtol*resid0 ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "converged due to relative tolerance"; + halt = true; + } + } + if( i == maxits ) + { +#if defined(USE_OMP) +#pragma omp single +#endif + { + reason = "reached maximum iteration number"; + halt = true; + } + } + i++; + } + } + //info->RestoreMatrix(A); + info->RestoreVector(SOL); + info->RestoreVector(RHS); + if( last_resid < atol || last_resid < rtol*resid0 ) return true; + return false; + } + bool ReplaceMAT(Sparse::Matrix & A) { if (isInitialized()) Finalize(); if (prec != NULL) prec->ReplaceMAT(A); Alink = &A; return true; } + bool ReplaceRHS(Sparse::Vector & RHS) {(void)RHS; return true; } + bool ReplaceSOL(Sparse::Vector & SOL) {(void)SOL; return true; } + Method * Duplicate() { return new BCGS_solver(*this);} + std::string GetReason() {return reason;} + + }; +} + + +#endif diff --git a/Source/Solver/solver_inner/solver_ilu2/CMakeLists.txt b/Source/Solver/solver_inner/solver_ilu2/CMakeLists.txt new file mode 100644 index 0000000..cdbd3f9 --- /dev/null +++ b/Source/Solver/solver_inner/solver_ilu2/CMakeLists.txt @@ -0,0 +1,6 @@ +set(SOURCE ${SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/SolverILU2.cpp) +set(HEADER ${HEADER} ${CMAKE_CURRENT_SOURCE_DIR}/solver_ilu2.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/SolverILU2.h) + +set(SOURCE ${SOURCE} PARENT_SCOPE) +set(HEADER ${HEADER} PARENT_SCOPE) \ No newline at end of file diff --git a/Source/Solver/solver_inner/solver_ilu2/SolverILU2.cpp b/Source/Solver/solver_inner/solver_ilu2/SolverILU2.cpp new file mode 100644 index 0000000..da663bd --- /dev/null +++ b/Source/Solver/solver_inner/solver_ilu2/SolverILU2.cpp @@ -0,0 +1,145 @@ +#include "SolverILU2.h" + +namespace INMOST { + + SolverILU2::SolverILU2() { + additive_schwartz_overlap = DEFAULT_ADDITIVE_SCHWARTZ_OVERLAP; + maximum_iterations = DEFAULT_MAXIMUM_ITERATIONS; + absolute_tolerance = DEFAULT_ABSOLUTE_TOLERANCE; + relative_tolerance = DEFAULT_RELATIVE_TOLERANCE; + divergence_tolerance = DEFAULT_DIVERGENCE_TOLERANCE; + + preconditioner_drop_tolerance = DEFAULT_PRECONDITIONER_DROP_TOLERANCE; + preconditioner_reuse_tolerance = DEFAULT_PRECONDITIONER_REUSE_TOLERANCE; + preconditioner_rescale_iterations = DEFAULT_PRECONDITIONER_RESCALE_ITERS; + preconditioner_fill_level = DEFAULT_PRECONDITIONER_FILL_LEVEL; + + Method *prec = new ILU2_preconditioner(info); + solver = new BCGS_solver(prec, info); + matrix = NULL; + } + + SolverILU2::SolverILU2(const SolverInterface* other) { + //You should not really want to copy solver's information + throw INMOST::SolverUnsupportedOperation; + } + + void SolverILU2::Assign(const SolverInterface* other) { + //You should not really want to copy solver's information + throw INMOST::SolverUnsupportedOperation; + } + + void SolverILU2::Initialize(int *argc, char ***argv, const char *parameters_file, std::string prefix) { + + } + + void SolverILU2::SetMatrix(Sparse::Matrix & A, bool ModifiedPattern, bool OldPreconditioner) { + Sparse::Matrix *m = new Sparse::Matrix(A); + info.PrepareMatrix(*m, additive_schwartz_overlap); + solver->ReplaceMAT(*m); + if (matrix != NULL) { + delete matrix; + } + matrix = m; + + solver->RealParameter(":tau") = preconditioner_drop_tolerance; + solver->RealParameter(":tau2") = preconditioner_reuse_tolerance; + solver->EnumParameter(":scale_iters") = preconditioner_rescale_iterations; + solver->EnumParameter(":fill") = static_cast(preconditioner_fill_level); + + if (!solver->isInitialized()) { + solver->Initialize(); + } + } + + bool SolverILU2::Solve(Sparse::Vector &RHS, Sparse::Vector &SOL) { + solver->EnumParameter("maxits") = maximum_iterations; + solver->RealParameter("rtol") = relative_tolerance; + solver->RealParameter("atol") = absolute_tolerance; + solver->RealParameter("divtol") = divergence_tolerance; + + return solver->Solve(RHS,SOL); + } + + bool SolverILU2::Clear() { + info.Clear(); + if (matrix != NULL) { + delete matrix; + matrix = NULL; + } + if (solver != NULL) { + delete solver; + solver = NULL; + } + return true; + } + + bool SolverILU2::isMatrixSet() { + return matrix != NULL; + } + + INMOST_DATA_REAL_TYPE SolverILU2::GetPropertyReal(std::string property) const { + return solver->RealParameter(property); + } + + INMOST_DATA_ENUM_TYPE SolverILU2::GetPropertyEnum(std::string property) const { + return solver->EnumParameter(property); + } + + void SolverILU2::SetPropertyReal(std::string property, INMOST_DATA_REAL_TYPE value) { + //Maybe we should use explicit names?, like maxits ..etc + //like solver->RealParameter(property) = value; + if (property == "absolute_tolerance") { + absolute_tolerance = value; + } else if (property == "relative_tolerance") { + relative_tolerance = value; + } else if (property == "divergence_tolerance") { + divergence_tolerance = value; + } else if (property == "drop_tolerance") { + preconditioner_drop_tolerance = value; + } else if (property == "reuse_tolerance") { + preconditioner_reuse_tolerance = value; + } else if (property == "fill_level") { + preconditioner_fill_level = value; + } else { + std::cout << "Parameter " << property << " of real type is unknown" << std::endl; + } + } + + void SolverILU2::SetPropertyEnum(std::string property, INMOST_DATA_ENUM_TYPE value) { + //Maybe we should use explicit names?, like maxits ..etc + //like solver->EnumParameter(property) = value; + if (property == "maximum_iterations") { + maximum_iterations = value; + } else if (property == "rescale_iterations") { + preconditioner_rescale_iterations = value; + } else if (property == "schwartz_overlap") { + additive_schwartz_overlap = value; + } else std::cout << "Parameter " << property << " of integral type is unknown" << std::endl; + } + + const INMOST_DATA_ENUM_TYPE SolverILU2::Iterations() const { + return solver->GetIterations(); + } + + const INMOST_DATA_REAL_TYPE SolverILU2::Residual() const { + return solver->GetResidual(); + } + + const std::string SolverILU2::ReturnReason() const { + return solver->GetReason(); + } + + const std::string SolverILU2::SolverName() const { + return "inner_ilu2"; + } + + void SolverILU2::Finalize() { + + } + + SolverILU2::~SolverILU2() { + Clear(); + } + +} \ No newline at end of file diff --git a/Source/Solver/solver_inner/solver_ilu2/SolverILU2.h b/Source/Solver/solver_inner/solver_ilu2/SolverILU2.h new file mode 100644 index 0000000..a19ca39 --- /dev/null +++ b/Source/Solver/solver_inner/solver_ilu2/SolverILU2.h @@ -0,0 +1,58 @@ +#ifndef INMOST_SOLVERILU2_H +#define INMOST_SOLVERILU2_H + +#include +#include "solver_ilu2.hpp" +#include "../solver_bcgsl.hpp" + +namespace INMOST { + + class SolverILU2 : public SolverInterface { + private: + Sparse::Matrix *matrix; + BCGS_solver *solver; + Solver::OrderInfo info; + + INMOST_DATA_ENUM_TYPE additive_schwartz_overlap; + + INMOST_DATA_ENUM_TYPE maximum_iterations; + INMOST_DATA_REAL_TYPE absolute_tolerance; + INMOST_DATA_REAL_TYPE relative_tolerance; + INMOST_DATA_REAL_TYPE divergence_tolerance; + + INMOST_DATA_REAL_TYPE preconditioner_drop_tolerance; + INMOST_DATA_REAL_TYPE preconditioner_reuse_tolerance; + INMOST_DATA_REAL_TYPE preconditioner_fill_level; + INMOST_DATA_ENUM_TYPE preconditioner_rescale_iterations; + public: + SolverILU2(); + SolverILU2(const SolverInterface* other); + + virtual void Assign(const SolverInterface* other); + + virtual void Initialize(int *argc, char ***argv, const char *parameters_file, std::string prefix); + virtual void SetMatrix(Sparse::Matrix & A, bool ModifiedPattern, bool OldPreconditioner); + virtual bool Solve(Sparse::Vector &RHS, Sparse::Vector &SOL); + virtual bool Clear(); + + virtual bool isMatrixSet(); + + virtual INMOST_DATA_REAL_TYPE GetPropertyReal(std::string property) const; + virtual INMOST_DATA_ENUM_TYPE GetPropertyEnum(std::string property) const; + + virtual void SetPropertyReal(std::string property, INMOST_DATA_REAL_TYPE value); + virtual void SetPropertyEnum(std::string property, INMOST_DATA_ENUM_TYPE value); + + virtual const INMOST_DATA_ENUM_TYPE Iterations() const; + virtual const INMOST_DATA_REAL_TYPE Residual() const; + virtual const std::string ReturnReason() const; + + virtual const std::string SolverName() const; + + virtual void Finalize(); + virtual ~SolverILU2(); + }; + +} + +#endif \ No newline at end of file diff --git a/Source/Solver/solver_inner/solver_ilu2/solver_ilu2.hpp b/Source/Solver/solver_inner/solver_ilu2/solver_ilu2.hpp new file mode 100644 index 0000000..dfb3df2 --- /dev/null +++ b/Source/Solver/solver_inner/solver_ilu2/solver_ilu2.hpp @@ -0,0 +1,530 @@ + +#ifndef __SOLVER_ILU2__ +#define __SOLVER_ILU2__ +#include + +#include "inmost_solver.h" +#include "../solver_prototypes.hpp" +//#define REPORT_ILU +//#define REPORT_ILU_PROGRESS +using namespace INMOST; + +#define DEFAULT_TAU 0.005 +#define DEFAULT_TAU2 0.00001 +//#define LFILL //control, that factorization is not less then fill for ilu2 + + + +class ILU2_preconditioner : public Method +{ +private: + + Sparse::Matrix * Alink; + Solver::OrderInfo * info; + //Sparse::Matrix L,U; + //Sparse::Vector div; + std::vector luv; + std::vector lui; + interval ilu,iu; + INMOST_DATA_ENUM_TYPE Lfill; + INMOST_DATA_REAL_TYPE tau, tau2; + Sparse::Vector DL, DR; + INMOST_DATA_ENUM_TYPE nnz, sciters; + bool init; +public: + INMOST_DATA_REAL_TYPE & RealParameter(std::string name) + { + if( name == "tau" ) return tau; + else if( name == "tau2" ) return tau2; + throw -1; + } + INMOST_DATA_ENUM_TYPE & EnumParameter(std::string name) + { + if (name == "fill") return Lfill; + else if (name == "scale_iters") return sciters; + throw -1; + } + ILU2_preconditioner(Solver::OrderInfo & info) + :info(&info),tau(DEFAULT_TAU), tau2(DEFAULT_TAU2) + { + Alink = NULL; + init = false; + sciters = 12; + Lfill = 1; + } + bool Initialize() + { + if (isInitialized()) Finalize(); + assert(Alink != NULL); + nnz = 0; + for (Sparse::Matrix::iterator it = (*Alink).Begin(); it != (*Alink).End(); ++it) nnz += it->Size(); +#if defined(LFILL) + std::vector lfill; + lfill.reserve(nnz * 4); +#endif + luv.reserve(nnz * 4); + lui.reserve(nnz * 4); + + + std::vector rv; + std::vector ri; + rv.reserve(nnz * 16); + ri.reserve(nnz * 16); + INMOST_DATA_ENUM_TYPE mobeg, moend, vlocbeg, vlocend, vbeg, vend, k, r, end, iter, j; + INMOST_DATA_REAL_TYPE leabs, flin, ldiag, udiag, mva; + INMOST_DATA_ENUM_TYPE curr, foll; + INMOST_DATA_ENUM_TYPE ind, jn; + INMOST_DATA_INTEGER_TYPE prev, ipred; + const INMOST_DATA_REAL_TYPE tol_modif = 1e-12, eps = 1.0e-54, subst = 1.0; + const INMOST_DATA_ENUM_TYPE UNDEF = ENUMUNDEF, EOL = ENUMUNDEF - 1; + //Calculate scaling vectors for matrix (from genebs) + info->GetOverlapRegion(info->GetRank(), mobeg, moend); + info->GetLocalRegion(info->GetRank(), vlocbeg, vlocend); + info->GetVectorRegion(vbeg, vend); + interval ir(mobeg, moend + 1); + interval RowValues(vbeg, vend); +#if defined(LFILL) + interval RowFill(vbeg, vend); + //std::fill(RowFill.begin(),RowFill.end(),ENUMUNDEF); +#endif + interval RowIndeces(vbeg - 1, vend); + + ilu.set_interval_beg(mobeg); + ilu.set_interval_end(moend + 1); + iu.set_interval_beg(mobeg); + iu.set_interval_end(moend); + ilu[mobeg] = 0; + ir[mobeg] = 0; +#if defined(REPORT_ILU) + std::cout << "Matrix overlap " << mobeg << ".." << moend << std::endl; + std::cout << "Local vector part " << vlocbeg << ".." << vlocend << std::endl; + std::cout << "Entire vector " << vbeg << ".." << vend << std::endl; +#endif + //Rescale Matrix + DL.SetInterval(mobeg, moend); + info->PrepareVector(DR); + for (k = mobeg; k < moend; k++) + { + for (Sparse::Row::iterator rit = (*Alink)[k].Begin(); rit != (*Alink)[k].End(); ++rit) DL[k] += rit->second*rit->second; + if (DL[k] < eps) DL[k] = 1.0 / subst; else DL[k] = 1.0 / DL[k]; + } + for (iter = 0; iter < sciters; iter++) + { + for(Sparse::Vector::iterator rit = DR.Begin(); rit != DR.End(); ++rit) *rit = 0.0; + for (k = vlocbeg; k < vlocend; k++) + for (Sparse::Row::iterator rit = (*Alink)[k].Begin(); rit != (*Alink)[k].End(); ++rit) DR[rit->first] += DL[k] * rit->second*rit->second; + info->Accumulate(DR); + info->Update(DR); + for (k = vlocbeg; k < vlocend; k++) if (DR[k] < eps) DR[k] = 1.0 / subst; else DR[k] = 1.0 / DR[k]; + for(Sparse::Vector::iterator rit = DL.Begin(); rit != DL.End(); ++rit) *rit = 0.0; + for (k = mobeg; k < moend; k++) + for (Sparse::Row::iterator rit = (*Alink)[k].Begin(); rit != (*Alink)[k].End(); ++rit) DL[k] += DR[rit->first] * rit->second*rit->second; + for (k = mobeg; k < moend; k++) if (DL[k] < eps) DL[k] = 1.0 / subst; else DL[k] = 1.0 / DL[k]; + } + for (k = mobeg; k < moend; k++) DL[k] = sqrt(DL[k]); + for (k = vbeg; k < vend; k++) DR[k] = sqrt(DR[k]); + for (k = mobeg; k < moend; k++) + for (Sparse::Row::iterator rit = (*Alink)[k].Begin(); rit != (*Alink)[k].End(); ++rit) + rit->second = DL[k] * rit->second * DR[rit->first]; + + //timer = Timer(); + for(interval::iterator it = RowIndeces.begin(); it != RowIndeces.end(); ++it) *it = UNDEF; + std::vector sort_indeces; + //INMOST_DATA_ENUM_TYPE nza = 0, nzl = 0, nzu = 0, nzu2 = 0; + //for(k = mobeg; k != moend; k++) nza += A[k].Size(); + for (k = mobeg; k != moend; k++) + { +#if defined(REPORT_ILU_PROGRESS) + if (k % 1000 == 0) + { + //std::cout << "precond: " << (double)(k-mobeg)/(double)(moend-mobeg)*100 << "\r"; + //printf("%6.2f nza %12d nzl %12d nzu %12d nzu2 %12d\r", (double)(k-mobeg)/(double)(moend-mobeg)*100,nza,nzl,nzu,nzu2); + printf("precond: %6.2f\r", (double)(k - mobeg) / (double)(moend - mobeg) * 100); + fflush(stdout); + } +#endif + //Uncompress row + //row_uncompr + Sparse::Row & Ak = (*Alink)[k]; + end = Ak.Size(); + sort_indeces.clear(); + for (r = 0; r < end; r++) if (fabs(Ak.GetValue(r)) > eps) + { + RowValues[Ak.GetIndex(r)] = Ak.GetValue(r); +#if defined(LFILL) + RowFill[Ak.GetIndex(r)] = 0; +#endif + ind = Ak.GetIndex(r); + sort_indeces.push_back(ind); + } + std::sort(sort_indeces.begin(), sort_indeces.end()); + prev = static_cast(vbeg)-1; + ipred = static_cast(vbeg)-1; + for (r = 0; r < sort_indeces.size(); r++) + { + ind = sort_indeces[r]; + RowIndeces[prev] = ind; + prev = static_cast(ind); + if (ind <= k) ipred = ind; + } + RowIndeces[prev] = EOL; + + if (ipred != static_cast(k)) + { + RowValues[k] = 0.0; +#if defined(LFILL) + RowFill[k] = 0; +#endif + ind = RowIndeces[ipred]; + RowIndeces[ipred] = k; + RowIndeces[k] = ind; + } +#if defined(DIAGONAL_PERTURBATION) + RowValues[k] = RowValues[k]*(1.0+DIAGONAL_PERTURBATION_REL) + (RowValues[k] < 0.0? -1.0 : 1.0)*DIAGONAL_PERTURBATION_REL; +#endif + //Eliminate lower part + //elim_lpart + j = RowIndeces[static_cast(vbeg)-1]; + while (j < k) //until diagonal entry + { + assert(lui[iu[j]] == j); + RowValues[j] *= luv[iu[j]]; //scale by diagonal + leabs = fabs(RowValues[j]); +#if defined(LFILL) + if (leabs > tau2*tau2)// introduce a non-zero, if threshold permits +#else + if (leabs > tau2)// introduce a non-zero, if threshold permits +#endif + { + curr = j; + for (r = iu[j] + 1; r < ilu[j + 1]; r++) + { + ind = lui[r]; + if (RowIndeces[ind] != UNDEF) //update without pondering on thresholds + { + RowValues[ind] -= RowValues[j] * luv[r]; +#if defined(LFILL) + RowFill[ind] = std::min(lfill[r]+1,RowFill[ind]); +#endif + } + else + { + flin = -RowValues[j] * luv[r]; + //insert new value + foll = curr; + while (foll < ind) + { + curr = foll; + foll = RowIndeces[curr]; + } + assert(curr < ind); + assert(ind < foll); + RowIndeces[curr] = ind; + RowIndeces[ind] = foll; + RowValues[ind] = flin; +#if defined(LFILL) + RowFill[ind] = lfill[r] + 1; +#endif + } + curr = ind; + } + + if (leabs > tau) + { + curr = j; + for (r = ir[j]; r < ir[j + 1]; r++) + { + //ind = U2j.GetIndex(r); + ind = ri[r]; + if (RowIndeces[ind] != UNDEF) //update without pondering on thresholds + RowValues[ind] -= RowValues[j] * rv[r]; + else // introduce a non-zero if threshold permits + { + flin = -RowValues[j] * rv[r]; + //insert new value + foll = curr; + while (foll < ind) + { + curr = foll; + foll = RowIndeces[curr]; + } + assert(curr < ind); + assert(ind < foll); + RowIndeces[curr] = ind; + RowIndeces[ind] = foll; + RowValues[ind] = flin; +#if defined(LFILL) + RowFill[ind] = ENUMUNDEF; +#endif + } + curr = ind; + } + } + } + j = RowIndeces[j]; + } + // Compress row + //row_compr + j = RowIndeces[static_cast(vbeg)-1]; + //find minimum value in row + ldiag = 0; + while (j != EOL) + { + INMOST_DATA_REAL_TYPE temp = fabs(RowValues[j]); + ldiag = std::max(ldiag, temp); + j = RowIndeces[j]; + } + if (ldiag < tau2) + { + ldiag = 1.0 / tau2; + //std::cout << "ldiag too small " << ldiag << std::endl; + } + else + ldiag = 1.0 / ldiag; + + //if (ldiag > 1000) std::cout << "ldiag is big " << k << " " << ldiag << std::endl; + //divide all entries on right from the diagonal + j = k; + while (j != EOL) + { + RowValues[j] *= ldiag; + j = RowIndeces[j]; + } + j = RowIndeces[static_cast(vbeg)-1]; + while (j < k) + { + mva = fabs(RowValues[j]); + if (mva > tau2*tau2 ) + { + if (mva > tau +#if defined(LFILL) + || RowFill[j] <= Lfill +#endif + ) + { + //L[k][j] = RowValues[j]; + lui.push_back(j); //lui indicates column index of L matrix + luv.push_back(RowValues[j]); //luv indicates corresponding value +#if defined(LFILL) + lfill.push_back(RowFill[j]); +#endif + //nzl++; + } + } + jn = RowIndeces[j]; + RowIndeces[j] = UNDEF; + j = jn; + } + //add last diagonal entry to L matrix + lui.push_back(k); + luv.push_back(ldiag); +#if defined(LFILL) + lfill.push_back(0); +#endif + //nzl++; + + iu[k] = static_cast(luv.size()); //iu points to the first entry of current line of U matrix + // END of L-part + if (fabs(RowValues[j]) > tol_modif) + udiag = 1.0 / RowValues[j]; + else + { + //std::cout << "udiag too small " << RowValues[j] << std::endl; + udiag = (RowValues[j] < 0.0 ? -1.0 : 1.0) / tol_modif; + } + + //if (fabs(udiag) > 1000) std::cout << "udiag is big " << k << " " << udiag << std::endl; + + jn = RowIndeces[j]; + RowIndeces[j] = UNDEF; + j = jn; + //start of U matrix entries + //add diagonal value for U matrix + lui.push_back(k); + luv.push_back(udiag); +#if defined(LFILL) + lfill.push_back(RowFill[k]); +#endif + //nzu++; + while (j != EOL) + { + mva = fabs(RowValues[j]); + if (mva > tau2*tau2) + { + if (mva > tau +#if defined(LFILL) + || RowFill[j] <= Lfill +#endif + ) + { + //add values to U matrix + lui.push_back(j); + luv.push_back(RowValues[j]); +#if defined(LFILL) + lfill.push_back(RowFill[j]); +#endif + //nzu++; + } + else if (mva > tau2) + { + //add values to U2 matrix + ri.push_back(j); + rv.push_back(RowValues[j]); + //nzu2++; + } + } + jn = RowIndeces[j]; + RowIndeces[j] = UNDEF; + j = jn; + } + ilu[k + 1] = static_cast(luv.size()); //next first entry for L + + ir[k + 1] = static_cast(rv.size()); //next first entry for U2 + //END U-part + } + //printf("\n"); + //std::cout << "iluoo_solve: " << Timer() - timer << std::endl; + //timer = Timer(); + //Rescale LU + //xxlusc + for (k = mobeg; k < moend; k++) + { + for (r = iu[k] - 1; r > ilu[k]; r--) + { + luv[r - 1] /= DL[k]; + //LFNORM += luv[r-1]*luv[r-1]; + } + luv[iu[k] - 1] *= DL[k]; // L diagonal entry + //LFNORM += luv[iu[k]-1]*luv[iu[k]-1]; + } + for (k = mobeg; k < moend; k++) + { + for (r = iu[k] + 1; r < ilu[k + 1]; r++) + { + luv[r] /= DR[lui[r]]; + //UFNORM += luv[r]*luv[r]; + } + luv[iu[k]] *= DR[k]; // U diagonal entry + //UFNORM += luv[iu[k]]*luv[iu[k]]; + } + //std::cout << "xxlusc: " << Timer() - timer << " LFNORM " << sqrt(LFNORM) << " UFNORM " << sqrt(UFNORM) << std::endl; + //timer = Timer(); + + + //Rescale matrix back + //matisc + for (k = mobeg; k < moend; k++) + for (Sparse::Row::iterator rit = (*Alink)[k].Begin(); rit != (*Alink)[k].End(); ++rit) + rit->second = rit->second / DL[k] / DR[rit->first]; + //std::cout << "matisc: " << Timer() - timer << std::endl; + +#if defined(REPORT_ILU) + INMOST_DATA_ENUM_TYPE nzu,nzl, nza; + nzu = 0; + nzl = 0; + nza = 0; + for(INMOST_DATA_ENUM_TYPE k = mobeg; k < moend; k++) + { + nzl += iu[k] - ilu[k]; + nzu += ilu[k+1] - iu[k] - 1; + nza += (*Alink)[k].Size(); + } + std::cout << " nonzeros in A = " << nza << std::endl; + std::cout << " nonzeros in L = " << nzl - (moend-mobeg) << std::endl; + std::cout << " nonzeros in U = " << nzu << std::endl; + std::cout << " nonzeros in LU = " << ilu[moend] - 1 << std::endl; + std::cout << " nonzeros in U2 = " << ir[moend] - 1 << std::endl; + //std::cout << __FUNCTION__ << " done" << std::endl; +#endif + + /* + info.PrepareVector(div); + std::fill(div.Begin(),div.End(),0); + for(k = mobeg; k < moend; k++) div[k] = 1.0; + info.Accumulate(div); + for(k = mobeg; k < moend; k++) div[k] = 1.0/div[k]; + */ + init = true; + return true; + } + bool isInitialized(){ return init; } + bool Finalize() + { + if (!isFinalized()) + { + luv.clear(); + lui.clear(); + init = false; + } + return true; + } + bool isFinalized() { return !init; } + ~ILU2_preconditioner() + { + if (!isFinalized()) Finalize(); + } + void Copy(const Method * other) + { + const ILU2_preconditioner * b = dynamic_cast(other); + assert(b != NULL); + info = b->info; + Alink = b->Alink; + DL = b->DL; + DR = b->DR; + nnz = b->nnz; + luv = b->luv; + lui = b->lui; + iu = b->iu; + ilu = b->ilu; + } + ILU2_preconditioner(const ILU2_preconditioner & other) + :Method(other) + { + Copy(&other); + } + ILU2_preconditioner & operator =(ILU2_preconditioner const & other) + { + Copy(&other); + return *this; + } + bool Solve(Sparse::Vector & input, Sparse::Vector & output) + { + assert(isInitialized()); +#if defined(USE_OMP) +#pragma omp single +#endif + { + INMOST_DATA_ENUM_TYPE mobeg, moend, r, k, vbeg,vend; //, end; + info->GetOverlapRegion(info->GetRank(),mobeg,moend); + info->GetVectorRegion(vbeg,vend); + for(k = vbeg; k < mobeg; k++) output[k] = 0; //Restrict additive schwartz (maybe do it outside?) + for(k = mobeg; k < moend; k++) output[k] = input[k]; + for(k = moend; k < vend; k++) output[k] = 0; //Restrict additive schwartz (maybe do it outside?) + for(k = mobeg; k < moend; k++) //iterate over L part + { + for(r = iu[k]-1; r > ilu[k]; r--) + output[k] -= luv[r-1]*output[lui[r-1]]; + output[k] *= luv[iu[k]-1]; + } + for(k = moend; k > mobeg; k--) //iterate over U part + { + for(r = iu[k-1]+1; r < ilu[k]; r++) + output[k-1] -= luv[r]*output[lui[r]]; + output[k-1] *= luv[iu[k-1]]; + } + } + //May assemble partition of unity instead of restriction before accumulation + //assembly should be done instead of initialization + info->Accumulate(output); + return true; + } + bool ReplaceMAT(Sparse::Matrix & A) { if (isInitialized()) Finalize(); Alink = &A; return true; }; + bool ReplaceSOL(Sparse::Vector & x) {(void)x;return true;} + bool ReplaceRHS(Sparse::Vector & b) {(void)b;return true;} + Method * Duplicate() { return new ILU2_preconditioner(*this); } +}; + + + + +#endif //__SOLVER_ILU2__ diff --git a/Source/Solver/solver_inner/solver_prototypes.hpp b/Source/Solver/solver_inner/solver_prototypes.hpp new file mode 100644 index 0000000..146e574 --- /dev/null +++ b/Source/Solver/solver_inner/solver_prototypes.hpp @@ -0,0 +1,39 @@ + +#ifndef __SOLVER_PROTOTYPES__ +#define __SOLVER_PROTOTYPES__ + +//TODO: +// allow user to provide new RHS or new initial solution + +#include "inmost_solver.h" + +using namespace INMOST; + +class Method +{ +public: + virtual INMOST_DATA_REAL_TYPE & RealParameter(std::string name) = 0; + virtual INMOST_DATA_ENUM_TYPE & EnumParameter(std::string name) = 0; + virtual bool Initialize() = 0; + virtual bool isInitialized() = 0; + virtual bool Finalize() = 0; + virtual bool isFinalized() = 0; + virtual bool Solve(Sparse::Vector & input, Sparse::Vector & output) = 0; + virtual bool ReplaceMAT(Sparse::Matrix & A) = 0; //provide matrix + virtual bool ReplaceRHS(Sparse::Vector & b) = 0; //apply modification such as rescaling or reordering to the new right hand side + virtual bool ReplaceSOL(Sparse::Vector & x) = 0; //apply modification such as rescaling or reordering to the new solution + virtual void Copy(const Method * other) = 0; + virtual Method * Duplicate() {return NULL;} + virtual ~Method() {} +}; + +class IterativeMethod : public Method +{ +public: + virtual INMOST_DATA_ENUM_TYPE GetIterations() = 0; + virtual INMOST_DATA_REAL_TYPE GetResidual() = 0; + virtual std::string GetReason() = 0; + virtual ~IterativeMethod() {} +}; + +#endif diff --git a/Source/Solver/solver_petsc/CMakeLists.txt b/Source/Solver/solver_petsc/CMakeLists.txt new file mode 100644 index 0000000..965dcc6 --- /dev/null +++ b/Source/Solver/solver_petsc/CMakeLists.txt @@ -0,0 +1,7 @@ +set(SOURCE ${SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/solver_petsc.cpp) +set(SOURCE ${SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/solver_petsc.h) +set(SOURCE ${SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/SolverPETSC.cpp) +set(HEADER ${HEADER} ${CMAKE_CURRENT_SOURCE_DIR}/SolverPETSc.h) + +set(SOURCE ${SOURCE} PARENT_SCOPE) +set(HEADER ${HEADER} PARENT_SCOPE) \ No newline at end of file diff --git a/Source/Solver/refactoring/solver_petsc/SolverPETSc.cpp b/Source/Solver/solver_petsc/SolverPETSc.cpp similarity index 93% rename from Source/Solver/refactoring/solver_petsc/SolverPETSc.cpp rename to Source/Solver/solver_petsc/SolverPETSc.cpp index f5a47fd..31ca87a 100644 --- a/Source/Solver/refactoring/solver_petsc/SolverPETSc.cpp +++ b/Source/Solver/solver_petsc/SolverPETSc.cpp @@ -1,7 +1,3 @@ -// -// Created by Dmitri Bagaev on 22.09.16. -// - #include "SolverPETSc.h" namespace INMOST { @@ -190,16 +186,32 @@ namespace INMOST { return result; } + bool SolverPETSc::Clear() { + local_size = global_size = 0; + if (matrix != NULL) { + MatrixDestroyDataPetsc(&matrix); + } + return true; + } + bool SolverPETSc::isMatrixSet() { return matrix != NULL; } INMOST_DATA_REAL_TYPE SolverPETSc::GetPropertyReal(std::string property) const { - throw NotImplemented; + throw INMOST::SolverUnsupportedOperation; } INMOST_DATA_ENUM_TYPE SolverPETSc::GetPropertyEnum(std::string property) const { - throw NotImplemented; + throw INMOST::SolverUnsupportedOperation; + } + + void SolverPETSc::SetPropertyReal(std::string property, INMOST_DATA_REAL_TYPE value) { + //throw INMOST::SolverUnsupportedOperation; + } + + void SolverPETSc::SetPropertyEnum(std::string property, INMOST_DATA_ENUM_TYPE value) { + //throw INMOST::SolverUnsupportedOperation; } const INMOST_DATA_ENUM_TYPE SolverPETSc::Iterations() const { diff --git a/Source/Solver/refactoring/solver_petsc/SolverPETSc.h b/Source/Solver/solver_petsc/SolverPETSc.h similarity index 85% rename from Source/Solver/refactoring/solver_petsc/SolverPETSc.h rename to Source/Solver/solver_petsc/SolverPETSc.h index 2f7b660..23aba75 100644 --- a/Source/Solver/refactoring/solver_petsc/SolverPETSc.h +++ b/Source/Solver/solver_petsc/SolverPETSc.h @@ -1,16 +1,9 @@ -// -// Created by Dmitri Bagaev on 22.09.16. -// - #ifndef INMOST_SOLVERPETSC_H #define INMOST_SOLVERPETSC_H -#include "petsc.h" #include "inmost.h" -#include "new_solver_petsc.h" -#include "Source/Solver/solver_petsc.h" -#include "Source/Solver/refactoring/SolverFactory.h" -#include "Source/Solver/refactoring/SolverInterface.h" +#include "petsc.h" +#include "solver_petsc.h" namespace INMOST { @@ -34,12 +27,16 @@ namespace INMOST { virtual void Initialize(int *argc, char ***argv, const char *parameters_file, std::string prefix); virtual void SetMatrix(Sparse::Matrix & A, bool ModifiedPattern, bool OldPreconditioner); virtual bool Solve(Sparse::Vector &RHS, Sparse::Vector &SOL); + virtual bool Clear(); virtual bool isMatrixSet(); virtual INMOST_DATA_REAL_TYPE GetPropertyReal(std::string property) const; virtual INMOST_DATA_ENUM_TYPE GetPropertyEnum(std::string property) const; + virtual void SetPropertyReal(std::string property, INMOST_DATA_REAL_TYPE value); + virtual void SetPropertyEnum(std::string property, INMOST_DATA_ENUM_TYPE value); + virtual const INMOST_DATA_ENUM_TYPE Iterations() const; virtual const INMOST_DATA_REAL_TYPE Residual() const; virtual const std::string ReturnReason() const; diff --git a/Source/Solver/refactoring/solver_petsc/new_solver_petsc.cpp b/Source/Solver/solver_petsc/solver_petsc.cpp similarity index 91% rename from Source/Solver/refactoring/solver_petsc/new_solver_petsc.cpp rename to Source/Solver/solver_petsc/solver_petsc.cpp index 5c970bb..2f2c60a 100644 --- a/Source/Solver/refactoring/solver_petsc/new_solver_petsc.cpp +++ b/Source/Solver/solver_petsc/solver_petsc.cpp @@ -1,49 +1,45 @@ -// -// Created by Dmitri Bagaev on 28.09.16. -// - #define _CRT_SECURE_NO_WARNINGS #include "inmost_solver.h" #if defined(USE_SOLVER) #if defined(USE_SOLVER_PETSC) #include -#include "new_solver_petsc.h" +#include "solver_petsc.h" #define PETSC_SUCCESS 0 -//bool SolverIsInitializedPetsc() -//{ -// PetscBool isInitialized; -// PetscErrorCode ierr = PetscInitialized(&isInitialized); -// if( ierr != PETSC_SUCCESS ) throw INMOST::ErrorInSolver; -// return (isInitialized == PETSC_TRUE); -//} -// -//void SolverInitializePetsc(int * argc,char *** argv, const char * file_options) -//{ -// if( !SolverIsInitializedPetsc() ) -// { -// PetscErrorCode ierr = PetscInitialize(argc,argv,file_options,"solver"); -// //prevent petsc from catching signals, petsc error handling is misleading for -// //unexperienced user and results in the opinion that errors emerge from petsc -// PetscPopSignalHandler(); -// if( ierr != PETSC_SUCCESS ) throw INMOST::ErrorInSolver; -// } -//} -// -//bool SolverIsFinalizedPetsc() -//{ -// PetscBool isFinalized; -// PetscErrorCode ierr = PetscFinalized(&isFinalized); -// if( ierr != PETSC_SUCCESS ) throw INMOST::ErrorInSolver; -// return (isFinalized == PETSC_TRUE); -//} -// -//void SolverFinalizePetsc() -//{ -// PetscErrorCode ierr = PetscFinalize(); -// if( ierr != PETSC_SUCCESS ) throw INMOST::ErrorInSolver; -//} +bool SolverIsInitializedPetsc() +{ + PetscBool isInitialized; + PetscErrorCode ierr = PetscInitialized(&isInitialized); + if( ierr != PETSC_SUCCESS ) throw INMOST::ErrorInSolver; + return (isInitialized == PETSC_TRUE); +} + +void SolverInitializePetsc(int * argc,char *** argv, const char * file_options) +{ + if( !SolverIsInitializedPetsc() ) + { + PetscErrorCode ierr = PetscInitialize(argc,argv,file_options,"solver"); + //prevent petsc from catching signals, petsc error handling is misleading for + //unexperienced user and results in the opinion that errors emerge from petsc + PetscPopSignalHandler(); + if( ierr != PETSC_SUCCESS ) throw INMOST::ErrorInSolver; + } +} + +bool SolverIsFinalizedPetsc() +{ + PetscBool isFinalized; + PetscErrorCode ierr = PetscFinalized(&isFinalized); + if( ierr != PETSC_SUCCESS ) throw INMOST::ErrorInSolver; + return (isFinalized == PETSC_TRUE); +} + +void SolverFinalizePetsc() +{ + PetscErrorCode ierr = PetscFinalize(); + if( ierr != PETSC_SUCCESS ) throw INMOST::ErrorInSolver; +} void MatrixDestroyDataPetsc(Mat **matrix) { diff --git a/Source/Solver/refactoring/solver_petsc/new_solver_petsc.h b/Source/Solver/solver_petsc/solver_petsc.h similarity index 91% rename from Source/Solver/refactoring/solver_petsc/new_solver_petsc.h rename to Source/Solver/solver_petsc/solver_petsc.h index 78eb139..3f617f6 100644 --- a/Source/Solver/refactoring/solver_petsc/new_solver_petsc.h +++ b/Source/Solver/solver_petsc/solver_petsc.h @@ -27,10 +27,10 @@ void VectorFillPetsc(Vec *vector, int size, int * positions, double * values); void VectorLoadPetsc(Vec *vector, int size, int * positions, double * values); void VectorFinalizePetsc(Vec *vector); -//bool SolverIsInitializedPetsc(); -//void SolverInitializePetsc(int * argc,char *** argv, const char * file_options); -//bool SolverIsFinalizedPetsc(); -//void SolverFinalizePetsc(); +bool SolverIsInitializedPetsc(); +void SolverInitializePetsc(int * argc,char *** argv, const char * file_options); +bool SolverIsFinalizedPetsc(); +void SolverFinalizePetsc(); void SolverInitDataPetsc(KSP **ksp, INMOST_MPI_Comm comm, const char * name); void SolverCopyDataPetsc(KSP **ksp, KSP *other_ksp, INMOST_MPI_Comm comm); -- 2.26.2