diff --git a/AMDiS/src/AMDiS.cc b/AMDiS/src/AMDiS.cc index 9ea6d73f083da4d98de20226545a14811d5dbb70..a5b3e4440152387dfe84bfe5566c53df33e3c90f 100644 --- a/AMDiS/src/AMDiS.cc +++ b/AMDiS/src/AMDiS.cc @@ -29,6 +29,10 @@ #endif #include "boost/program_options.hpp" +#if defined HAVE_PETSC || defined HAVE_SEQ_PETSC || defined HAVE_PARALLEL_PETSC +#include <petsc.h> +#endif + namespace AMDiS { using namespace std; diff --git a/AMDiS/src/AMDiS.h b/AMDiS/src/AMDiS.h index f27c34ab5bf960bbc7790114e6c34920cc51d161..762b35de9cd50b1b3113a15e727f1942717c06d5 100644 --- a/AMDiS/src/AMDiS.h +++ b/AMDiS/src/AMDiS.h @@ -154,9 +154,7 @@ #include "parallel/StdMpi.h" #include "parallel/ParallelProblemStat.h" -#if HAVE_PARALLEL_MTL4 -// #include "parallel/PMTL4Solver.h" -#else +#if !HAVE_PARALLEL_MTL4 #include "parallel/PetscSolver.h" #include "parallel/PetscSolverNavierStokes.h" #endif diff --git a/AMDiS/src/AMDiS_fwd.h b/AMDiS/src/AMDiS_fwd.h index 8ea6e49f88d3556b3926bc6af5576ff1a31f8996..229f7616bb889209759a59f03cde371a1cc5eb6b 100644 --- a/AMDiS/src/AMDiS_fwd.h +++ b/AMDiS/src/AMDiS_fwd.h @@ -35,6 +35,7 @@ namespace AMDiS { class AdaptStationary; class Assembler; class BasisFunction; + struct BlockMTLMatrix; class BoundaryManager; // class CGSolver; class CoarseningManager; diff --git a/AMDiS/src/CreatorMap.cc b/AMDiS/src/CreatorMap.cc index 36c001a8c01c40d1a375f2830be0ff5748df194f..5a88adb91654713a267e15eea6676c9a66d2cce0 100644 --- a/AMDiS/src/CreatorMap.cc +++ b/AMDiS/src/CreatorMap.cc @@ -25,6 +25,7 @@ #include "MTL4Types.h" #include "solver/LinearSolver.h" #include "solver/ITL_Solver.h" +#include "solver/BITL_Solver.h" #include "solver/ITL_Preconditioner.h" #include "solver/UmfPackSolver.h" #include "solver/KrylovPreconditioner.h" @@ -61,6 +62,9 @@ namespace AMDiS { { LinearSolverCreator *creator; + // creators for MTL4 krylov solvers + // _________________________________________________________________________ + creator = new CGSolver::Creator; addCreator("mtl_cg", creator); @@ -115,11 +119,64 @@ namespace AMDiS { addCreator("mtl_hypre", creator); #endif + // creators for block krylov solvers + // _________________________________________________________________________ + + creator = new B_CGSolver::Creator; + addCreator("bmtl_cg", creator); + + creator = new B_CGSSolver::Creator; + addCreator("bmtl_cgs", creator); + +// creator = new B_BiCGSolver::Creator; +// addCreator("mtl_bicg", creator); + + creator = new B_BiCGStabSolver::Creator; + addCreator("bmtl_bicgstab", creator); + +// creator = new B_BiCGStab2Solver::Creator; +// addCreator("bmtl_bicgstab2", creator); // MTL Error + +// creator = new B_BiCGStabEllSolver::Creator; +// addCreator("bmtl_bicgstab_ell", creator); // MTL Error + +// creator = new QMRSolver::Creator; +// addCreator("mtl_qmr", creator); + + creator = new B_TFQMRSolver::Creator; + addCreator("bmtl_tfqmr", creator); + + creator = new B_GMResSolver::Creator; + addCreator("bmtl_gmres", creator); + + creator = new B_GcrSolver::Creator; + addCreator("bmtl_gcr", creator); + + creator = new B_FGMResSolver::Creator; + addCreator("bmtl_fgmres", creator); + +// creator = new B_IDRsSolver::Creator; +// addCreator("bmtl_idr_s", creator); // MTL Error + + creator = new B_MinResSolver::Creator; + addCreator("bmtl_minres", creator); + + creator = new B_PreOnly::Creator; + addCreator("bmtl_preonly", creator); + addCreator("bmtl_richardson", creator); + + // creators for PETSc solvers + // _________________________________________________________________________ + #if defined HAVE_SEQ_PETSC // sequential PETSc-Solver - creator = new PetscSolver<>::Creator; + creator = new PetscSolver::Creator; addCreator("petsc_petsc", creator); // standard creator for petsc solver addCreator("petsc", creator); + + LinearSolverCreator* creator2 = new PetscSolverNested::Creator; + addCreator("bpetsc_petsc", creator2); // standard creator for petsc solver + addCreator("bpetsc", creator2); std::map<std::string,std::string>::iterator it; PetscParameters params; @@ -127,7 +184,8 @@ namespace AMDiS { it!= params.solverMap.end(); it++) { CreatorMap< LinearSolver >::addCreator("petsc_" + it->first, creator); - } + CreatorMap< LinearSolver >::addCreator("bpetsc_" + it->first, creator2); + } #endif } @@ -159,6 +217,22 @@ namespace AMDiS { } + template<> + void CreatorMap<ITL_BasePreconditioner<BlockMTLMatrix, MTLTypes::MTLVector> >::addDefaultCreators() + { + addCreator("no", new BlockIdentityPreconditioner::Creator); + addCreator("diag", new BlockDiagonalPreconditioner::Creator); + } + + +#if defined HAVE_SEQ_PETSC + template<> + void CreatorMap<PetscPreconditioner>::addDefaultCreators() { } + + template<> + void CreatorMap<PetscPreconditionerNested>::addDefaultCreators() { } +#endif + template<> void CreatorMap<Estimator>::addDefaultCreators() { diff --git a/AMDiS/src/CreatorMap.h b/AMDiS/src/CreatorMap.h index 212fd6727c0ae0fabaae392cfbd1942bf62872cb..8da0c1fe7d647a3dcfc755a8454485bbeb946419 100644 --- a/AMDiS/src/CreatorMap.h +++ b/AMDiS/src/CreatorMap.h @@ -43,13 +43,16 @@ namespace AMDiS { template<typename BaseClass> class CreatorMap { + public: + typedef std::map< std::string, CreatorInterface<BaseClass>* > CreatorMapType; + public: /// Adds a new creator together with the given key to the map. static void addCreator(std::string key, CreatorInterface<BaseClass>* creator) { FUNCNAME("CreatorMap::addCreator()"); init(); - TEST_EXIT(creatorMap[key] == nullptr) + TEST_EXIT(creatorMap[key] == NULL) ("there is already a creator for key %s\n",key.c_str()); creatorMap[key] = creator; } @@ -66,8 +69,10 @@ namespace AMDiS { FUNCNAME("CreatorMap::getCreator()"); init(); CreatorInterface<BaseClass> *creator = creatorMap[key]; - TEST_EXIT(creator)("No creator for key \"%s\" defined in init file for parameter \"%s\"\n", - key.c_str(), initFileStr.c_str()); + TEST_EXIT(creator) + ("No creator for key \"%s\" defined in init file for parameter \"%s\"\n", + key.c_str(), initFileStr.c_str()); + return creator; } @@ -89,13 +94,13 @@ namespace AMDiS { protected: /// STL map containing the pairs of keys and creators. - static std::map< std::string, CreatorInterface<BaseClass>* > creatorMap; + static CreatorMapType creatorMap; static bool initialized; }; template<typename BaseClass> - std::map< std::string, CreatorInterface<BaseClass>* > CreatorMap<BaseClass>::creatorMap; + typename CreatorMap<BaseClass>::CreatorMapType CreatorMap<BaseClass>::creatorMap; template<typename BaseClass> bool CreatorMap<BaseClass>::initialized = false; diff --git a/AMDiS/src/DOFMatrix.cc b/AMDiS/src/DOFMatrix.cc index ea2aae87bc72470d2edca30644acfcf51f542380..a4960615119cc1b7ee0e939075a9c6bc56e9c55f 100644 --- a/AMDiS/src/DOFMatrix.cc +++ b/AMDiS/src/DOFMatrix.cc @@ -67,10 +67,6 @@ namespace AMDiS { if (!colFeSpace) colFeSpace = rowFeSpace; -#if 0 - if (rowFeSpace && rowFeSpace->getAdmin()) - (const_cast<DOFAdmin*>(rowFeSpace->getAdmin()))->addDOFIndexed(this); -#endif boundaryManager = new BoundaryManager(rowFeSpace); nRow = rowFeSpace->getBasisFcts()->getNumber(); @@ -87,10 +83,6 @@ namespace AMDiS { FUNCNAME("DOFMatrix::DOFMatrix()"); *this = rhs; -#if 0 - if (rowFeSpace && rowFeSpace->getAdmin()) - (const_cast<DOFAdmin*>( rowFeSpace->getAdmin()))->addDOFIndexed(this); -#endif TEST_EXIT(rhs.inserter == 0)("Cannot copy during insertion!\n"); inserter = 0; } @@ -98,10 +90,6 @@ namespace AMDiS { DOFMatrix::~DOFMatrix() { -#if 0 - if (rowFeSpace && rowFeSpace->getAdmin()) - (const_cast<DOFAdmin*>(rowFeSpace->getAdmin()))->removeDOFIndexed(this); -#endif if (boundaryManager) delete boundaryManager; if (inserter) @@ -116,43 +104,6 @@ namespace AMDiS { } - bool DOFMatrix::symmetric() - { - double tol = 1e-5; - - using mtl::tag::major; using mtl::tag::nz; using mtl::begin; using mtl::end; - namespace traits= mtl::traits; - typedef base_matrix_type Matrix; - - traits::row<Matrix>::type row(matrix); - traits::col<Matrix>::type col(matrix); - traits::const_value<Matrix>::type value(matrix); - - typedef traits::range_generator<major, Matrix>::type cursor_type; - typedef traits::range_generator<nz, cursor_type>::type icursor_type; - - for (cursor_type cursor = begin<major>(matrix), cend = end<major>(matrix); cursor != cend; ++cursor) - for (icursor_type icursor = begin<nz>(cursor), icend = end<nz>(cursor); icursor != icend; ++icursor) - // Compare each non-zero entry with its transposed - if (abs(value(*icursor) - matrix[col(*icursor)][row(*icursor)]) > tol) - return false; - return true; - } - - - void DOFMatrix::test() - { - FUNCNAME("DOFMatrix::test()"); - - int non_symmetric = !symmetric(); - - if (non_symmetric) - MSG("Matrix `%s' not symmetric.\n", name.data()); - else - MSG("Matrix `%s' is symmetric.\n", name.data()); - } - - DOFMatrix& DOFMatrix::operator=(const DOFMatrix& rhs) { rowFeSpace = rhs.rowFeSpace; @@ -290,14 +241,11 @@ namespace AMDiS { } +#if 0 double DOFMatrix::logAcc(DegreeOfFreedom a, DegreeOfFreedom b) const { return matrix[a][b]; } - -#if 0 - void DOFMatrix::freeDOFContent(int index) - {} #endif void DOFMatrix::assemble(double factor, @@ -418,7 +366,7 @@ namespace AMDiS { void DOFMatrix::finishAssembling() { - // call the operatos cleanup procedures + // call the operators cleanup procedures for (std::vector<Operator*>::iterator it = operators.begin(); it != operators.end(); ++it) (*it)->finishAssembling(); @@ -436,7 +384,7 @@ namespace AMDiS { return fillFlag; } - +#if 0 void DOFMatrix::axpy(double a, const DOFMatrix& x, const DOFMatrix& y) { matrix += a * x.matrix + y.matrix; @@ -447,7 +395,7 @@ namespace AMDiS { { matrix *= b; } - +#endif void DOFMatrix::addOperator(Operator *op, double* factor, double* estFactor) { diff --git a/AMDiS/src/DOFMatrix.h b/AMDiS/src/DOFMatrix.h index 7f44bb925cdfa296ff5725a9ed3e5402f19aeb46..f104cf23ff326579dfbb95eba7f682100f51a2ff 100644 --- a/AMDiS/src/DOFMatrix.h +++ b/AMDiS/src/DOFMatrix.h @@ -69,6 +69,9 @@ namespace AMDiS { /// Symbolic constant for an unused entry which is not followed by any /// used entry in this row static const int NO_MORE_ENTRIES = -2; + + /// Minimal slot-size used for the inserter. See \ref startInsertion for details. + static const int MIN_NNZ_PER_ROW = 20; public: DOFMatrix(); @@ -100,56 +103,7 @@ namespace AMDiS { { return matrix; } -#if 0 - // Only to get rid of the abstract functions, I hope they are not used - std::vector<bool>::iterator begin() - { - ERROR_EXIT("Shouldn't be used, only fake."); std::vector<bool> v; - return v.begin(); - } - - std::vector<bool>::iterator end() - { - ERROR_EXIT("Shouldn't be used, only fake."); std::vector<bool> v; - return v.end(); - } - - // Only to get rid of the abstract functions, I hope they are not used - std::vector<bool>::const_iterator begin() const - { - ERROR_EXIT("Shouldn't be used, only fake."); std::vector<bool> v; - return v.begin(); - } - - std::vector<bool>::const_iterator end() const - { - ERROR_EXIT("Shouldn't be used, only fake."); std::vector<bool> v; - return v.end(); - } - - bool dummy; // Must be deleted later - reference operator[](DegreeOfFreedom i) - { - ERROR_EXIT("Shouldn't be used, only fake."); - std::vector<bool> d; d.push_back(dummy); - return d[0]; - } - - const_reference operator[](DegreeOfFreedom i) const - { - ERROR_EXIT("Shouldn't be used, only fake."); - std::vector<bool> d; d.push_back(dummy); - return d[0]; - } - - /// DOFMatrix does not need to be compressed before assembling, when using MTL4. - void compressDOFIndexed(int first, int last, std::vector<DegreeOfFreedom> &newDOF) - {} - - /// Implements DOFIndexedBase::freeDOFContent() - virtual void freeDOFContent(int index); -#endif /// Returns \ref coupleMatrix. inline bool isCoupleMatrix() { @@ -162,11 +116,13 @@ namespace AMDiS { coupleMatrix = c; } +#if 0 /// a * x + y void axpy(double a, const DOFMatrix& x, const DOFMatrix& y); /// Multiplication with a scalar. void scal(double s); +#endif /// Adds an operator to the DOFMatrix. A factor, that is multipled to the /// operator, and a multilier factor for the estimator may be also given. @@ -267,7 +223,7 @@ namespace AMDiS { /// entries per row (per column for CCS matrices). Choosing this parameter /// too small can induce perceivable overhead for compressed matrices. Thus, /// it's better to choose a bit too large than too small. - void startInsertion(int nnz_per_row = 10); + void startInsertion(int nnz_per_row = MIN_NNZ_PER_ROW); /// Finishes insertion. For compressed matrix types, this is where the /// compression happens. @@ -281,15 +237,6 @@ namespace AMDiS { inserter= 0; } -#if 0 - /// Returns whether restriction should be performed after coarsening - /// (false by default) - virtual bool coarseRestrict() - { - return false; - } -#endif - /// Returns const \ref rowFeSpace const FiniteElemSpace* getRowFeSpace() const { @@ -332,12 +279,6 @@ namespace AMDiS { return name; } #if 0 - /// Resizes \ref matrix to n rows - inline void resize(int n) - { - TEST_EXIT_DBG(n >= 0)("Can't resize DOFMatrix to negative size\n"); - } -#endif /// Returns value at logical indices a,b double logAcc(DegreeOfFreedom a, DegreeOfFreedom b) const; @@ -349,6 +290,7 @@ namespace AMDiS { void addSparseDOFEntry(double sign, int irow, int jcol, double entry, bool add = true); +#endif void clearDirichletRows(); @@ -361,11 +303,6 @@ namespace AMDiS { set_to_zero(matrix); } - /// Test whether \ref matrix is symmetric. Exits if not. - void test(); - - bool symmetric(); - inline std::vector<Operator*>& getOperators() { return operators; @@ -398,8 +335,8 @@ namespace AMDiS { if (num_rows(matrix) != 0) nnzPerRow = int(double(matrix.nnz()) / num_rows(matrix) * 1.2); - if (nnzPerRow < 20) - nnzPerRow = 20; + if (nnzPerRow < MIN_NNZ_PER_ROW) + nnzPerRow = MIN_NNZ_PER_ROW; } /// Returns \ref nnzPerRow. diff --git a/AMDiS/src/DOFVector.cc b/AMDiS/src/DOFVector.cc index 7d46bc825b076db07bbb67a67ee70f8631261eee..f396a8144e3d09dab7d29b46c42dd963d562fd39 100644 --- a/AMDiS/src/DOFVector.cc +++ b/AMDiS/src/DOFVector.cc @@ -110,7 +110,7 @@ namespace AMDiS { delete oldElInfo; } else inside = mesh->findElInfoAtPoint(p, elInfo, lambda, nullptr, nullptr, nullptr); - + if (oldElInfo) oldElInfo = elInfo; @@ -122,7 +122,7 @@ namespace AMDiS { value = basFcts->evalUh(lambda, uh); } else { #ifdef HAVE_PARALLEL_DOMAIN_AMDIS - return 0.0; + value = 0.0; #else ERROR_EXIT("Can not eval DOFVector at point p, because point is outside geometry."); #endif @@ -132,6 +132,9 @@ namespace AMDiS { if (oldElInfo == nullptr) delete elInfo; +#ifdef HAVE_PARALLEL_DOMAIN_AMDIS + Parallel::mpi::globalAdd(value); +#endif return value; } diff --git a/AMDiS/src/GenericOperatorTerm.h b/AMDiS/src/GenericOperatorTerm.h index d703d1e6b39a5113a553ba754c97980aac8ac0ab..6114c21ab79eb7926162e46921765d2bdaa54680 100644 --- a/AMDiS/src/GenericOperatorTerm.h +++ b/AMDiS/src/GenericOperatorTerm.h @@ -315,7 +315,7 @@ struct GenericSecondOrderTerm_1 : public SecondOrderTerm l1lt(grdLambda, LALt[iq], term(iq)); } - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -336,7 +336,7 @@ struct GenericSecondOrderTerm_1 : public SecondOrderTerm } } - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result) { @@ -521,25 +521,6 @@ inline void addZOT(Operator& op, double term) addZOT(op, constant(term)); } - -// ............................................................................. -// Rosenbrock method - -// template <typename Term> -// void addZOT_(Operator* op, const Term& term) -// { -// if (op->getUhOld()) { -// addZOT(op, jacobian(term,0) * ... -// -// } - -// template <typename Term> -// void addZOT(Operator& op, const Term& term) -// { -// op.addZeroOrderTerm(new GenericZeroOrderTerm<Term>(term)); -// } - - // _____________________________________________________________________________ // first order term using FirstOrderTerm::l1 @@ -775,7 +756,7 @@ inline expressions::Function1<expressions::Wrapper<TOut,WorldVector<double> >, e eval(AbstractFunction<TOut, WorldVector<double> >* fct) { return function_(wrap(fct), X()); } /// Integrate an expression over a domain. -/** IF the expression does not contain any DOFVector, a mesh must be given as second argument */ +/** If the expression does not contain any DOFVector, a mesh must be given as second argument */ template<typename Term> inline typename boost::enable_if<typename traits::is_expr<Term>::type, typename Term::value_type>::type integrate(Term term, Mesh* mesh_ = NULL); diff --git a/AMDiS/src/Global.cc b/AMDiS/src/Global.cc index da9725d28ce1dd612512d0e05d34fd7fd95a07d7..beae250a82f4080d4e8410b99f08b2dadb9e4574 100644 --- a/AMDiS/src/Global.cc +++ b/AMDiS/src/Global.cc @@ -188,7 +188,11 @@ namespace AMDiS { PRINT_LINE((*error), buff); va_end(arg); #if defined HAVE_PARALLEL_DOMAIN_AMDIS && !defined HAVE_PARALLEL_MTL4 && (DEBUG == 0 || defined NDEBUG) + #if (PETSC_VERSION_MINOR >= 5) + PetscError(MPI_COMM_WORLD, __LINE__, "Msg::print_error_exit", "Global.cc", 1, PETSC_ERROR_INITIAL, buff); + #else PetscError(MPI_COMM_WORLD, __LINE__, "Msg::print_error_exit", "Global.cc", "src/", 1, PETSC_ERROR_INITIAL, buff); + #endif #else throw std::runtime_error(buff); #endif diff --git a/AMDiS/src/LinearAlgebra.h b/AMDiS/src/LinearAlgebra.h new file mode 100644 index 0000000000000000000000000000000000000000..7b29384f524729b1ec4957db0f3246f69ca3b144 --- /dev/null +++ b/AMDiS/src/LinearAlgebra.h @@ -0,0 +1,239 @@ +/****************************************************************************** + * + * AMDiS - Adaptive multidimensional simulations + * + * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved. + * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis + * + * Authors: + * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * + * This file is part of AMDiS + * + * See also license.opensource.txt in the distribution. + * + ******************************************************************************/ + + /// This file is work in progress and may replace the assembling now part of + /// DOFMatrix directly. The idea is to assemble matrices to a data-structure + /// provided by a linear algebra backend. You have to specify how an element- + /// matrix can be added to the global matrix, how a Dirichlet-row is inserted + /// and how the matrix is initialized/finalized. + + +/** \file LinearAlgebra.h */ + +#ifndef AMDIS_LINEAR_ALGEBRA_H +#define AMDIS_LINEAR_ALGEBRA_H + +#include "utility/calculate_nnz.hpp" + +namespace AMDiS { + + namespace tag + { + struct distributed {}; + struct non_distributed {}; + + // backends + struct mtl {}; + struct pmtl {}; + struct petsc {}; + struct p_petsc {}; + } + + namespace traits + { + template< class T > + struct distributed_tag : boost::mpl::if_< + mtl::traits::is_distributed< T >, + tag::distributed, + tag::non_distributed + > {}; + } + + namespace detail + { + template< class Dummy = void > + struct DefaultParameters {}; + } + + /** fill for each backend a linear algebra class that + * contains the following typedefs and functions + **/ + template< class Backend = tag::mtl, class Value = double, class Parameters = detail::DefaultParameters<> > + struct LinearAlgebra + { + public: // typedefs + + typedef Value ValueType; + typedef unsigned int SizeType; + + typedef mtl::matrix::parameters<mtl::row_major, mtl::index::c_index, mtl::non_fixed::dimensions, false, SizeType> MatrixPara; + typedef mtl::matrix::compressed2D<ValueType, MatrixPara> MatrixBase; + typedef mtl::vector::dense_vector<ValueType> VectorBase; + + typedef mtl::matrix::inserter<MatrixBase, mtl::operations::update_plus<ValueType> > Inserter; + typedef MPI::Intracomm Communicator; + + static const int minSlotSize = 20; + + public: // methods + + /// constructor + LinearAlgebra(Communicator& comm) + : comm(comm), ins(NULL) + { } + + + /// prepare matrix for insertion + template< class M > + void init_matrix(MatrixBase& matrix, MapperBase<M>& mapper, bool add_to_matrix = false) + { + int slot_size = estimate_slot_size(matrix); + prepare_matrix(matrix, mapper, traits::distributed_tag<MatrixBase>::type() ); + + if (!add_to_matrix) + set_to_zero(matrix); + + // prepare the inserter + if (ins) { + delete ins; + ins = NULL; + } + ins = new Inserter(matrix, slot_size); + } + + + /// finish insertion + template< class M > + void exit_matrix(MatrixBase& matrix, MapperBase<M>& mapper) + { + // destroy inserter, to start insertion + assert( ins ); + delete ins; + inserter = NULL; + } + + + /// insert values of element_matrix into matrix + template< class ElementMatrix, class VectorType > + void add_element_matrix(MatrixBase& matrix, const ElementMatrix& elMatrix, + const VectorType& rowIndices, const VectorType& colIndices) + { + assert( ins ); + *ins << mtl::matrix::element_matrix(elMatrix, rowIndices, colIndices); + } + + protected: // methods + + /// resize matrix to appropriate size + template< class M > + void prepare_matrix(MatrixBase& matrix, MapperBase<M>& mapper, tag::non_distributed) + { + matrix.change_dim(mapper.getNumRows(), mapper.getNumCols()); + } + + + /// estimate the number of nonzeros per row + int estimate_slot_size(const MatrixBase& matrix) + { + int nnzPerRow = 0; + if (num_rows(matrix) != 0) + nnzPerRow = static_cast<int>((matrix.nnz() * 1.2) / num_rows(matrix)); + return std::max( nnzPerRow, minSlotSize ); + } + + private: // member variables + Communicator& comm; + Inserter* ins; + }; + +#ifdef HAVE_PARALLEL_MTL4 + template< class Value, class Parameters > + struct LinearAlgebra< tag::pmtl, Value, Parameters > : public LinearAlgebra< tag::mtl, Value, Parameters > + { + typedef LinearAlgebra< tag::mtl, Value, Parameters > super; + + /// constructor + LinearAlgebra(Communicator& comm) + : super(comm) + { } + + protected: + // eventuell als freie funktion schreiben + template< class M > + void prepare_matrix(MatrixBase& matrix, MapperBase<M>& mapper, tag::distributed) + { + mtl::par::block_distribution dist(mapper.getNumRows()); + dist.setup_from_local_size(mapper.getMap().getLocalDofs()); + matrix.change_dim(0, 0); + matrix.init_distribution(dist, dist, mapper.getNumRows(), mapper.getNumRows()); + } + }; +#endif + + +#ifdef HAVE_SEQ_PETSC + template< class Value, class Parameters > + struct LinearAlgebra< tag::petsc, Value, Parameters > + { + public: // typedefs + + typedef PetscValue ValueType; + typedef PetscInt SizeType; + + typedef PetscMatrix MatrixBase; + typedef PetscVector VectorBase; + + typedef MPI::Intracomm Communicator; + + public: // methods + + /// constructor + LinearAlgebra(Communicator& comm) + : comm(comm) + { } + + + /// prepare matrix for insertion + template< class M > + void init_matrix(MatrixBase& mat, MapperBase<M>& mapper, bool add_to_matrix = false) + { + std::vector<size_t> nnz_per_row(mapper.getNumRows()); + calculate_nnz(dof_matrix /* ?? */, nnz_per_row); // siehe auch MatrixNnzStructure fuer parallele NNZ + + // eventuell nur max_nnz angeben + MatCreateSeqAIJ(comm, mapper.getNumRows(), mapper.getNumCols(), 0, &(nnz_per_row[0]), &mat.matrix); + } + + + /// finish insertion + template< class M > + void exit_matrix(MatrixBase& mat, MapperBase<M>& mapper) + { + MatAssemblyBegin(mat.matrix, MAT_FINAL_ASSEMBLY); + MatAssemblyEnd(mat.matrix, MAT_FINAL_ASSEMBLY); + } + + + /// insert values of element_matrix into matrix + template< class ElementMatrix, class VectorType > + void add_element_matrix(MatrixBase& mat, const ElementMatrix& elMatrix, + const VectorType& rowIndices, const VectorType& colIndices) + { + // delete dirichlet-dofs by changing the sign of these indices + MatSetValues(mat.matrix, rowIndices.size(), &rowIndices[0], colIndices.size(), &colIndices[0], elMatrix.address_data(), ADD_VALUES); + } + + private: // member variables + Communicator& comm; + }; +#endif +} + +#endif // AMDIS_DOFMATRIX_H diff --git a/AMDiS/src/ProblemInstat.cc b/AMDiS/src/ProblemInstat.cc index 8b2f9df4bbb88aba879c8c49aad372bc0563b66a..43e51a434139c376ef8f2e2d840b7ec1191d5de5 100644 --- a/AMDiS/src/ProblemInstat.cc +++ b/AMDiS/src/ProblemInstat.cc @@ -89,13 +89,16 @@ namespace AMDiS { ProblemStatBase &initialProb) : ProblemInstatBase(sname, &initialProb), problemStat(&prob), - oldSolution(nullptr) + oldSolution(NULL) {} ProblemInstat::~ProblemInstat() { - delete oldSolution; + if (oldSolution) { + delete oldSolution; + oldSolution = NULL; + } } @@ -153,7 +156,8 @@ namespace AMDiS { lastTimepoint = MPI::Wtime(); #endif - oldSolution->copy(*(problemStat->getSolution())); + if (oldSolution) + oldSolution->copy(*(problemStat->getSolution())); } } diff --git a/AMDiS/src/ProblemStat.cc b/AMDiS/src/ProblemStat.cc index e17ef11c2e698514892e6766dc80f6aeae8964c4..1e767bcccf8c7c2c1369ba3019b6d9a22d2fe0cd 100644 --- a/AMDiS/src/ProblemStat.cc +++ b/AMDiS/src/ProblemStat.cc @@ -676,7 +676,7 @@ namespace AMDiS { std::string componentName = ""; Parameters::get(numberedName + "->name", componentName); std::vector<std::string> names; - if (name != "") + if (componentName != "") names.push_back(componentName); std::vector<int> comp; Parameters::get(numberedName + "->components", comp); diff --git a/AMDiS/src/SecondOrderTerm.h b/AMDiS/src/SecondOrderTerm.h index 3b285a05a8419dbfebd70ae7e19b72f5c1dc4548..0ba96dc117f7e859b827cb5c60c59fc06ba1422a 100644 --- a/AMDiS/src/SecondOrderTerm.h +++ b/AMDiS/src/SecondOrderTerm.h @@ -140,7 +140,7 @@ namespace AMDiS { l1lt(grdLambda, LALt[iq], (*factor)); } - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -161,7 +161,7 @@ namespace AMDiS { } } - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result) { @@ -200,7 +200,7 @@ namespace AMDiS { /// Implements SecondOrderTerm::getLALt(). void getLALt(const ElInfo *elInfo, std::vector<mtl::dense2D<double> > &LALt) const; - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -208,7 +208,7 @@ namespace AMDiS { mtl::dense_vector<double>& result, double factor); - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result); @@ -257,7 +257,7 @@ namespace AMDiS { lalt(Lambda, matrix, LALt[iq], symmetric, 1.0); } - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -265,7 +265,7 @@ namespace AMDiS { mtl::dense_vector<double>& result, double factor); - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result); @@ -317,7 +317,7 @@ namespace AMDiS { lalt_kl(grdLambda, xi, xj, LALt[iq], (*factor)); } - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -330,7 +330,7 @@ namespace AMDiS { result[iq] += (*factor) * D2UhAtQP[iq][xi][xj] * fac; } - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result) { @@ -376,7 +376,7 @@ namespace AMDiS { /// Implements SecondOrderTerm::getLALt(). void getLALt(const ElInfo *elInfo, std::vector<mtl::dense2D<double> > &LALt) const; - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -384,7 +384,7 @@ namespace AMDiS { mtl::dense_vector<double>& result, double factor); - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result); @@ -425,7 +425,7 @@ namespace AMDiS { /// Implements SecondOrderTerm::getLALt(). void getLALt(const ElInfo *elInfo, std::vector<mtl::dense2D<double> > &LALt) const; - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -433,7 +433,7 @@ namespace AMDiS { mtl::dense_vector<double>& result, double factor); - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result); @@ -475,7 +475,7 @@ namespace AMDiS { /// Implements SecondOrderTerm::getLALt(). void getLALt(const ElInfo *elInfo, std::vector<mtl::dense2D<double> > &LALt) const; - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -483,7 +483,7 @@ namespace AMDiS { mtl::dense_vector<double>& result, double factor); - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result); @@ -527,7 +527,7 @@ namespace AMDiS { /// Implements SecondOrderTerm::getLALt(). void getLALt(const ElInfo *elInfo, std::vector<mtl::dense2D<double> > &LALt) const; - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -535,7 +535,7 @@ namespace AMDiS { mtl::dense_vector<double>& result, double factor); - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result); @@ -584,7 +584,7 @@ namespace AMDiS { /// Implements SecondOrderTerm::getLALt(). void getLALt(const ElInfo *elInfo, std::vector<mtl::dense2D<double> > &LALt) const; - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -592,7 +592,7 @@ namespace AMDiS { mtl::dense_vector<double>& result, double factor); - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result); @@ -634,7 +634,7 @@ namespace AMDiS { /// Implements SecondOrderTerm::getLALt(). void getLALt(const ElInfo *elInfo, std::vector<mtl::dense2D<double> > &LALt) const; - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -642,7 +642,7 @@ namespace AMDiS { mtl::dense_vector<double>& result, double factor); - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result); @@ -690,7 +690,7 @@ namespace AMDiS { /// Implements SecondOrderTerm::getLALt(). void getLALt(const ElInfo *elInfo, std::vector<mtl::dense2D<double> > &LALt) const; - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -698,7 +698,7 @@ namespace AMDiS { mtl::dense_vector<double>& result, double factor); - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result); @@ -791,7 +791,7 @@ namespace AMDiS { /// Implements SecondOrderTerm::getLALt(). void getLALt(const ElInfo *elInfo, std::vector<mtl::dense2D<double> > &LALt) const; - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -799,7 +799,7 @@ namespace AMDiS { mtl::dense_vector<double>& result, double factor); - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result); @@ -839,7 +839,7 @@ namespace AMDiS { /// Implements SecondOrderTerm::getLALt(). void getLALt(const ElInfo *elInfo, std::vector<mtl::dense2D<double> > &LALt) const; - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -847,7 +847,7 @@ namespace AMDiS { mtl::dense_vector<double>& result, double factor); - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result); @@ -889,7 +889,7 @@ namespace AMDiS { /// Implements SecondOrderTerm::getLALt(). void getLALt(const ElInfo *elInfo, std::vector<mtl::dense2D<double> > &LALt) const; - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -897,7 +897,7 @@ namespace AMDiS { mtl::dense_vector<double>& result, double factor); - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result); @@ -947,7 +947,7 @@ namespace AMDiS { /// Implements SecondOrderTerm::getLALt(). void getLALt(const ElInfo *elInfo, std::vector<mtl::dense2D<double> > &LALt) const; - /// Implenetation of SecondOrderTerm::eval(). + /// Implemetation of SecondOrderTerm::eval(). void eval(int nPoints, const mtl::dense_vector<double>& uhAtQP, const mtl::dense_vector<WorldVector<double> >& grdUhAtQP, @@ -955,7 +955,7 @@ namespace AMDiS { mtl::dense_vector<double>& result, double factor); - /// Implenetation of SecondOrderTerm::weakEval(). + /// Implemetation of SecondOrderTerm::weakEval(). void weakEval(const std::vector<WorldVector<double> > &grdUhAtQP, std::vector<WorldVector<double> > &result); diff --git a/AMDiS/src/expressions/cmath_expr.hpp b/AMDiS/src/expressions/cmath_expr.hpp index f99b978e6c566d1be64fbce4943ad8e1581cd970..ccfa46eea201f1d1186a9c96222eefcdca5b5c95 100644 --- a/AMDiS/src/expressions/cmath_expr.hpp +++ b/AMDiS/src/expressions/cmath_expr.hpp @@ -65,7 +65,7 @@ namespace AMDiS int getDegree() const { - return 0; + return 2*super::term.getDegree(); } inline value_type operator()(const int& iq) const { return (super::term(iq) > 0.0 ? 1.0 : -1.0); } @@ -83,7 +83,7 @@ namespace AMDiS Ceil(const Term& term_) : super(term_) {} - int getDegree() const { return 0; } + int getDegree() const { return super::term.getDegree(); } inline value_type operator()(const int& iq) const { return std::ceil(super::term(iq)); } @@ -100,7 +100,7 @@ namespace AMDiS Floor(const Term& term_) : super(term_) {} - int getDegree() const { return 0; } + int getDegree() const { return super::term.getDegree(); } inline value_type operator()(const int& iq) const { return std::floor(super::term(iq)); } diff --git a/AMDiS/src/expressions/expressions.h b/AMDiS/src/expressions/expressions.h index 78e27b953c332210f1178d832cd5b09d63cb30cb..7f27ea1ee68ad469e629ff7aa62c7ab0abb5a04e 100644 --- a/AMDiS/src/expressions/expressions.h +++ b/AMDiS/src/expressions/expressions.h @@ -30,6 +30,7 @@ #include "coords_expr.hpp" // coordinates / normal vectors #include "valueOf.hpp" // value of DOFVector at QPs #include "gradientOf.hpp" // gradient of DOFVector at QPs +#include "hessianOf.hpp" // second derivatives of DOFVector at QPs #include "add_expr.hpp" // add two expressions #include "mult_expr.hpp" // multiply two expressions diff --git a/AMDiS/src/expressions/hessianOf.hpp b/AMDiS/src/expressions/hessianOf.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1bb19bcca07caf8ae6f907605ab48be4151a97b2 --- /dev/null +++ b/AMDiS/src/expressions/hessianOf.hpp @@ -0,0 +1,234 @@ +/****************************************************************************** + * + * AMDiS - Adaptive multidimensional simulations + * + * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved. + * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis + * + * Authors: + * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * + * This file is part of AMDiS + * + * See also license.opensource.txt in the distribution. + * + ******************************************************************************/ + + + +/** \file hessianOf.hpp */ + +#ifndef AMDIS_HESSIAN_OF_HPP +#define AMDIS_HESSIAN_OF_HPP + +#include "AMDiS_fwd.h" +#include "LazyOperatorTerm.h" +#include "DOFVector.h" +#include "traits/category.hpp" + +namespace AMDiS +{ + namespace expressions + { + /// Expressions that extracts the gradient of a DOFVector at QPs + template<typename Vector, typename Name> + struct HessianOf : public LazyOperatorTermBase + { + typedef typename traits::category<Vector>::value_type T; + typedef typename D2Type<T>::type value_type; + typedef Name id; + + DOFVector<T>* vecDV; + mutable mtl::dense_vector<value_type> vec; + mutable mtl::dense_vector<T> coeff; + + HessianOf(Vector& vector) : vecDV(&vector) {} + HessianOf(Vector* vector) : vecDV(vector) {} + + template<typename List> + void insertFeSpaces(List& feSpaces) const + { + feSpaces.insert(vecDV->getFeSpace()); + } + + int getDegree() const + { + return vecDV->getFeSpace()->getBasisFcts()->getDegree() /* -1 */; + } + + template<typename OT> + void initElement(OT* ot, const ElInfo* elInfo, + SubAssembler* subAssembler, Quadrature *quad, + const BasisFunction *basisFct = NULL) + { FUNCNAME("HessianOf::initElement"); + + if (ot && subAssembler) { + ERROR_EXIT("Hessian expression not yet implemented for operator-terms!\n"); + } else if (quad) + vecDV->getD2AtQPs(elInfo, quad, NULL, vec); + else if (basisFct) { + const BasisFunction *localBasisFct = vecDV->getFeSpace()->getBasisFcts(); + + // get coefficients of DOFVector + coeff.change_dim(localBasisFct->getNumber()); + vecDV->getLocalVector(elInfo->getElement(), coeff); + + // eval basisfunctions of DOFVector at coords of given basisFct + size_t nBasisFct = basisFct->getNumber(); + vec.change_dim(nBasisFct); + + const DimVec<WorldVector<double> > &grdLambda = elInfo->getGrdLambda(); + for (size_t i = 0; i < nBasisFct; i++) + localBasisFct->evalD2Uh(*basisFct->getCoords(i), grdLambda, coeff, &vec[i]); + } + } + + + template<typename OT> + inline void initElement(OT* ot, const ElInfo* smallElInfo, const ElInfo* largeElInfo, + SubAssembler* subAssembler, Quadrature *quad, + const BasisFunction *basisFct = NULL) + { FUNCNAME("HessianOf::initElement"); + + ERROR_EXIT("Hessian expression not yet implemented for Dual-mesh!\n"); + } + + value_type operator()(const int& iq) const { return vec[iq]; } + + std::string str() const { return std::string("hessian(") + vecDV->getName() + ")"; } + }; + + + /// Expressions that extracts the partial derivative of a DOFVector at QPs + template<typename Vector, typename Name> + struct LaplacianOf : public LazyOperatorTermBase + { + typedef typename traits::category<Vector>::value_type T; + typedef T value_type; + typedef Name id; + + DOFVector<T>* vecDV; + mutable mtl::dense_vector<typename D2Type<T>::type> vec_tmp; + mutable mtl::dense_vector<value_type> vec; + mutable mtl::dense_vector<T> coeff; + int comp; + + LaplacianOf(Vector& vector) : vecDV(&vector) { } + LaplacianOf(Vector* vector) : vecDV(vector) { } + + template<typename List> + void insertFeSpaces(List& feSpaces) const + { + feSpaces.insert(vecDV->getFeSpace()); + } + + int getDegree() const + { + return vecDV->getFeSpace()->getBasisFcts()->getDegree() /* -1 */; + } + + template<typename OT> + void initElement(OT* ot, const ElInfo* elInfo, + SubAssembler* subAssembler, Quadrature *quad, + const BasisFunction *basisFct = NULL) + { FUNCNAME("LaplacianOf::initElement"); + + if (ot && subAssembler) { + ERROR_EXIT("Laplacian expression not yet implemented for operator-terms!\n"); + } else if (quad) { + vecDV->getD2AtQPs(elInfo, quad, NULL, vec_tmp); + for (size_t i = 0; i < size(vec_tmp); i++) { + vec[i] = vec_tmp[i][0][0]; + for (int j = 1; j < Global::getGeo(WORLD); j++) + vec[i] += vec_tmp[i][j][j]; + } + } else if (basisFct) { + const BasisFunction *localBasisFct = vecDV->getFeSpace()->getBasisFcts(); + + // get coefficients of DOFVector + coeff.change_dim(localBasisFct->getNumber()); + vecDV->getLocalVector(elInfo->getElement(), coeff); + + // eval basisfunctions of DOFVector at coords of given basisFct + size_t nBasisFct = basisFct->getNumber(); + vec.change_dim(nBasisFct); + WorldMatrix<double> hessian; + + const DimVec<WorldVector<double> > &grdLambda = elInfo->getGrdLambda(); + for (size_t i = 0; i < nBasisFct; i++) { + localBasisFct->evalD2Uh(*basisFct->getCoords(i), grdLambda, coeff, &hessian); + vec[i] = hessian[0][0]; + for (int j = 1; j < Global::getGeo(WORLD); j++) + vec[i] += hessian[j][j]; + } + } + } + + template<typename OT> + void initElement(OT* ot, const ElInfo* smallElInfo, const ElInfo* largeElInfo, + SubAssembler* subAssembler, Quadrature *quad, + const BasisFunction *basisFct = NULL) + { FUNCNAME("LaplacianOf::initElement"); + + ERROR_EXIT("Laplacian expression not yet implemented for Dual-mesh!\n"); + } + + value_type operator()(const int& iq) const { return vec[iq]; } + + std::string str() const { return std::string("laplace(") + vecDV->getName() + ")"; } + }; + + } // end namespace expressions + + + // gradient of a DOFVector + // _____________________________________________________________________________ + + // with Name + template<typename Name, typename T> + expressions::HessianOf<DOFVector<T>, Name > hessianOf(DOFVector<T>& vector) + { return expressions::HessianOf<DOFVector<T>, Name >(vector); } + + template<typename Name, typename T> + expressions::HessianOf<DOFVector<T>, Name > hessianOf(DOFVector<T>* vector) + { return expressions::HessianOf<DOFVector<T>, Name >(vector); } + + // without Name + template<typename T> + expressions::HessianOf<DOFVector<T>, _unknown > hessianOf(DOFVector<T>& vector) + { return expressions::HessianOf<DOFVector<T>, _unknown >(vector); } + + template<typename T> + expressions::HessianOf<DOFVector<T>, _unknown > hessianOf(DOFVector<T>* vector) + { return expressions::HessianOf<DOFVector<T>, _unknown >(vector); } + + + // Partial derivative of a DOFVector + // _____________________________________________________________________________ + + // with Name + template<typename Name, typename T> + expressions::LaplacianOf<DOFVector<T>, Name > laplacianOf(DOFVector<T>& vector) + { return expressions::LaplacianOf<DOFVector<T>, Name >(vector); } + + template<typename Name, typename T> + expressions::LaplacianOf<DOFVector<T>, Name > laplacianOf(DOFVector<T>* vector) + { return expressions::LaplacianOf<DOFVector<T>, Name >(vector); } + + // without Name + template<typename T> + expressions::LaplacianOf<DOFVector<T>, _unknown > laplacianOf(DOFVector<T>& vector) + { return expressions::LaplacianOf<DOFVector<T>, _unknown >(vector); } + + template<typename T> + expressions::LaplacianOf<DOFVector<T>, _unknown > laplacianOf(DOFVector<T>* vector) + { return expressions::LaplacianOf<DOFVector<T>, _unknown >(vector); } + +} // end namespace AMDiS + + +#endif // AMDIS_HESSIAN_OF_HPP diff --git a/AMDiS/src/parallel/MatrixNnzStructure.cc b/AMDiS/src/parallel/MatrixNnzStructure.cc index dbfb1d45d79fe71d99e1a850a26889a17992658c..0c514c7bf3f77348d9ca1c589a8dc4f30878340e 100644 --- a/AMDiS/src/parallel/MatrixNnzStructure.cc +++ b/AMDiS/src/parallel/MatrixNnzStructure.cc @@ -58,11 +58,11 @@ namespace AMDiS { namespace Parallel { { FUNCNAME("MatrixNnzStructure::create()"); - int nRankRows = rowDofMap.getRankDofs(); - int rankStartRowIndex = rowDofMap.getStartDofs(); + int nRankRows = rowDofMap.getRankDofs(); // Number of DOFs owned by rank. + int rankStartRowIndex = rowDofMap.getStartDofs(); // Smallest global index of a DOF owned by the rank. int nRankCols = colDofMap.getRankDofs(); - int nOverallCols = colDofMap.getOverallDofs(); + int nOverallCols = colDofMap.getOverallDofs(); // Number of global DOFs (this value is thus the same on all ranks). int rankStartColIndex = colDofMap.getStartDofs(); create(nRankRows, (!localMatrix ? nRankRows : -1)); @@ -139,7 +139,7 @@ namespace AMDiS { namespace Parallel { // === Prepare MTL4 iterators for the current DOF matrix. === - Matrix baseMat = dofMat->getBaseMatrix(); + Matrix baseMat = dofMat->getBaseMatrix(); // TBD: warum hier keine Referenz? traits::col<Matrix>::type getCol(baseMat); traits::row<Matrix>::type getRow(baseMat); diff --git a/AMDiS/src/parallel/MeshDistributor.cc b/AMDiS/src/parallel/MeshDistributor.cc index dfbb9dc838a8e621ac1eeb653b2909652c16bd29..d57739321f31c65dcf5bf605b428ecdd2bfe2b0f 100644 --- a/AMDiS/src/parallel/MeshDistributor.cc +++ b/AMDiS/src/parallel/MeshDistributor.cc @@ -1294,7 +1294,7 @@ namespace AMDiS { namespace Parallel { getImbalanceFactor(imbalanceFactor, minDofs, maxDofs, sumDofs); if (mpiRank == 0) - MSG("Imbalancing factor: %.2f [ minDofs = %d, maxDofs = %d, sumDofs = %d ]\n", + MSG("Imbalancing factor: %.2f %% [ minDofs = %d, maxDofs = %d, sumDofs = %d ]\n", imbalanceFactor * 100.0, minDofs, maxDofs, sumDofs); } @@ -1447,13 +1447,11 @@ namespace AMDiS { namespace Parallel { int repartitioning = 0; double imbalanceFactor = getImbalanceFactor(); + double imbalanceRepartitionBound = 0.2; + Parameters::get("parallel->repartitioning->imbalance", + imbalanceRepartitionBound); if (mpiRank == 0) { - double imbalanceRepartitionBound = 0.2; - Parameters::get("parallel->repartitioning->imbalance", - imbalanceRepartitionBound); - - if (imbalanceFactor > imbalanceRepartitionBound) repartitioning = 1; @@ -1461,6 +1459,11 @@ namespace AMDiS { namespace Parallel { } else { mpiComm.Bcast(&repartitioning, 1, MPI_INT, 0); } +#if (DEBUG != 0) + if (repartitioning == 0) { + MSG("imbalanceFactor = %f < %f = imbalanceRepartitionBound\n", imbalanceFactor, imbalanceRepartitionBound); + } +#endif return (repartitioning != 0); } diff --git a/AMDiS/src/parallel/PITL_Solver.h b/AMDiS/src/parallel/PITL_Solver.h index 905f9acfb0c01fd06f6de175301b0e2a7332d1cc..0836c788f2b504f4483b6ebc030297601e37d670 100644 --- a/AMDiS/src/parallel/PITL_Solver.h +++ b/AMDiS/src/parallel/PITL_Solver.h @@ -37,10 +37,10 @@ namespace AMDiS using namespace MTLTypes; template< typename SolverType > - struct PITL_Solver : MTL4Solver< PMTLMatrix, PMTLVector, ITL_Runner< SolverType, PMTLMatrix, PMTLVector >, true > + struct PITL_Solver : MTL4Solver< PMTLMatrix, PMTLVector, ITL_Runner< SolverType, PMTLMatrix, PMTLVector > > { PITL_Solver(std::string name) - : MTL4Solver< PMTLMatrix, PMTLVector, ITL_Runner< SolverType, PMTLMatrix, PMTLVector >, true >(name) {} + : MTL4Solver< PMTLMatrix, PMTLVector, ITL_Runner< SolverType, PMTLMatrix, PMTLVector > >(name) {} }; typedef PITL_Solver< cg_solver_type > P_CGSolver; diff --git a/AMDiS/src/parallel/PMTL4Solver.h b/AMDiS/src/parallel/PMTL4Solver.h deleted file mode 100644 index dfbfb47338149c870725562e566d11f800530a97..0000000000000000000000000000000000000000 --- a/AMDiS/src/parallel/PMTL4Solver.h +++ /dev/null @@ -1,114 +0,0 @@ -/****************************************************************************** - * - * AMDiS - Adaptive multidimensional simulations - * - * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved. - * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis - * - * Authors: - * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al. - * - * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE - * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * - * This file is part of AMDiS - * - * See also license.opensource.txt in the distribution. - * - ******************************************************************************/ - - -/** \file PMtl4Solver.h */ - -#ifndef AMDIS_PMTL4_SOLVER_H -#define AMDIS_PMTL4_SOLVER_H - -#ifdef HAVE_PARALLEL_MTL4 - -#include "solver/MTL4SolverBase.h" -#include "parallel/ParallelSolver.h" - -namespace AMDiS { - - namespace Parallel { - - - /** \ingroup Solver - * - * \brief - * Wrapper class for different PMTL4 solvers. These solvers - * are parametrized by Matrix- and VectorType. The different - * algorithms, like krylov subspace methods or other external - * solvers where PMTL4 provides an interface, can be assigned - * by different Runner objects. - **/ - template< typename MatrixType, typename VectorType, typename Runner > - class PMTL4Solver : public ParallelSolver, protected MTL4SolverBase<MatrixType, VectorType, Runner> - { - public: - typedef PMTL4Solver<MatrixType, VectorType, Runner> self; - typedef MTL4SolverBase<MatrixType, VectorType, Runner> details; - - using details::solve; - - /// Creator class used in the LinearSolverMap. - class Creator : public LinearSolverCreator - { - public: - virtual ~Creator() {} - - /// Returns a new MTL4Solver object. - LinearSolver* create() - { - return new self(this->name); - } - }; - - /// Constructor - PMTL4Solver(std::string n) - : ParallelSolver(n, false), - details(this) - {} - - - /// Implementation of \ref LinearSolver::getRunner() - virtual OEMRunner* getRunner() - { - return details::getRunner(); - } - - - /// Implementation of \ref LinearSolver::getLeftPrecon() - virtual OEMPreconditioner* getLeftPrecon() - { - return details::getLeftPrecon(); - } - - - /// Implementation of \ref LinearSolver::getRightPrecon() - virtual OEMPreconditioner* getRightPrecon() - { - return details::getRightPrecon(); - } - - protected: - /// Implementation of \ref LinearSolver::solveLinearSystem() - virtual int solveLinearSystem(const SolverMatrix<Matrix<DOFMatrix*> >& A, - SystemVector& x, - SystemVector& b, - bool createMatrixData, - bool storeMatrixData) - { - ParallelMapper mapper(*ParallelSolver::getDofMapping()); - return details::solve(A, x, b, mapper, createMatrixData, storeMatrixData); - } - }; - - } // end namespace Parallel -} // end namespace AMDiS - -#endif // HAVE_PARALLEL_MTL4 - -#endif // AMDIS_PMTL4_SOLVER_H - diff --git a/AMDiS/src/parallel/ParallelCoarseSpaceSolver.cc b/AMDiS/src/parallel/ParallelCoarseSpaceSolver.cc index 88cb0def56bc98903f707de65338d8632955d26a..e372bd8484e5b9ba1bf7903aeadb34d731395a45 100644 --- a/AMDiS/src/parallel/ParallelCoarseSpaceSolver.cc +++ b/AMDiS/src/parallel/ParallelCoarseSpaceSolver.cc @@ -84,6 +84,7 @@ namespace AMDiS { namespace Parallel { } + /// initializes vecSol, vecRhs, mat und componentIthCoarseMap void ParallelCoarseSpaceSolver::prepare() { FUNCNAME("ParallelCoarseSpaceSolver:prepare()"); diff --git a/AMDiS/src/parallel/PetscHelper.cc b/AMDiS/src/parallel/PetscHelper.cc index f49ba98981dbc5c61df82a772914cf0f8da5b151..d053a5096bc6063b92484750e12b6d85acf222e3 100644 --- a/AMDiS/src/parallel/PetscHelper.cc +++ b/AMDiS/src/parallel/PetscHelper.cc @@ -327,6 +327,25 @@ namespace AMDiS rtol, atol, maxIt); } + + void createSolver(MPI::Intracomm comm, KSP &ksp, Mat m, std::string kspPrefix, int info) + { + KSPCreate(comm, &ksp); + #if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(ksp, m, m); + #else + KSPSetOperators(ksp, m, m, SAME_NONZERO_PATTERN); + #endif + KSPSetTolerances(ksp, 0.0, 1e-8, PETSC_DEFAULT, PETSC_DEFAULT); + KSPSetType(ksp, KSPBCGS); + KSPSetOptionsPrefix(ksp, kspPrefix.c_str()); + + if (info >= 10) + KSPMonitorSet(ksp, KSPMonitorDefault, PETSC_NULL, PETSC_NULL); + else if (info >= 20) + KSPMonitorSet(ksp, KSPMonitorTrueResidualNorm, PETSC_NULL, PETSC_NULL); + } + } // end namespace petsc_helper } // end namespace Parallel } // end namespace AMDiS diff --git a/AMDiS/src/parallel/PetscHelper.h b/AMDiS/src/parallel/PetscHelper.h index b9f8a29a210f1d15ba8c4f2bc87b37ff828f490a..d102f463abca8f0c3c29344be5b87dc87030a829 100644 --- a/AMDiS/src/parallel/PetscHelper.h +++ b/AMDiS/src/parallel/PetscHelper.h @@ -115,6 +115,8 @@ namespace AMDiS PetscReal rtol = PETSC_DEFAULT, PetscReal atol = PETSC_DEFAULT, PetscInt maxIt = PETSC_DEFAULT); + + void createSolver(MPI::Intracomm comm, KSP &ksp, Mat m, std::string kspPrefix = "", int info = 0); } // end namespace petsc_helper } // end namespace Parallel diff --git a/AMDiS/src/parallel/PetscSolver.cc b/AMDiS/src/parallel/PetscSolver.cc index f3e666df3443bb95849d1c85eef1b0e8dbf09540..3f00e4e4503b260503647943796b863c85cf3373 100644 --- a/AMDiS/src/parallel/PetscSolver.cc +++ b/AMDiS/src/parallel/PetscSolver.cc @@ -74,12 +74,13 @@ namespace AMDiS { namespace Parallel { super::init(fe0, fe1, createGlobalMapping); } - int PetscSolver::solveLinearSystem(const SolverMatrix<Matrix<DOFMatrix*> >& A, + /// see seq::MTL4Solver::solveLinearSystem(...) + int PetscSolver::solveLinearSystem(const SolverMatrix<Matrix<DOFMatrix*> >& A, SystemVector& x, SystemVector& b, bool createMatrixData, bool storeMatrixData) - { + { FUNCNAME("PetscSolver::solveLinearSystem()"); TEST_EXIT(meshDistributor)("No meshDistributor provided. Should not happen!\n"); @@ -103,7 +104,7 @@ namespace AMDiS { namespace Parallel { } return 0; - } + } void PetscSolver::fillPetscMatrix(DOFMatrix* mat) { @@ -113,6 +114,7 @@ namespace AMDiS { namespace Parallel { } + /// see seq::PetscSolver::solve(const MatrixType& A, VectorType& x, const VectorType& b) void PetscSolver::solve(Vec &rhs, Vec &sol) { PetscErrorCode solverError = KSPSolve(kspInterior, rhs, sol); @@ -135,6 +137,7 @@ namespace AMDiS { namespace Parallel { } + /// was soll das denn genau machen? void PetscSolver::solveGlobal(Vec &rhs, Vec &sol) { FUNCNAME("PetscSolver::solveGlobal()"); @@ -149,6 +152,7 @@ namespace AMDiS { namespace Parallel { } + /// -> Helper-Funktion, benötigt nur domainComm void PetscSolver::copyVec(Vec& originVec, Vec& destVec, std::vector<int>& originIndex, std::vector<int>& destIndex) { @@ -178,6 +182,7 @@ namespace AMDiS { namespace Parallel { } + /// -> Helper-Funktion bool PetscSolver::testMatrixSymmetric(Mat mat, bool advancedTest) { FUNCNAME("PetscSolver::testMatrixSymmetric()"); diff --git a/AMDiS/src/parallel/PetscSolverCahnHilliard.cc b/AMDiS/src/parallel/PetscSolverCahnHilliard.cc index 76fb678d743b2c4f14edff295d85aac69ec5224b..ae6352b2b9a9b05df8268fc371f2e114d4d1bca4 100644 --- a/AMDiS/src/parallel/PetscSolverCahnHilliard.cc +++ b/AMDiS/src/parallel/PetscSolverCahnHilliard.cc @@ -85,7 +85,11 @@ namespace AMDiS { namespace Parallel { { // Create FGMRES based outer solver KSPCreate(meshDistributor->getMpiComm(0), &ksp); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(ksp, getMatInterior(), getMatInterior()); +#else KSPSetOperators(ksp, getMatInterior(), getMatInterior(), SAME_NONZERO_PATTERN); +#endif if (getInfo() >= 10) KSPMonitorSet(ksp, KSPMonitorDefault, PETSC_NULL, PETSC_NULL); else if (getInfo() >= 20) diff --git a/AMDiS/src/parallel/PetscSolverCahnHilliard2.cc b/AMDiS/src/parallel/PetscSolverCahnHilliard2.cc index e71ac593c08a4e214c8011362de6b26da994d694..f901be28b1fd4eadf6b74181114345463df7898f 100644 --- a/AMDiS/src/parallel/PetscSolverCahnHilliard2.cc +++ b/AMDiS/src/parallel/PetscSolverCahnHilliard2.cc @@ -67,7 +67,11 @@ namespace AMDiS { namespace Parallel { /// create new solver for S KSP kspS; KSPCreate(*data->mpiCommGlobal, &kspS); - KSPSetOperators(kspS, S, S, SAME_NONZERO_PATTERN); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(kspS, S, S); +#else + KSPSetOperators(kspS, S, S, SAME_NONZERO_PATTERN); +#endif petsc_helper::setSolver(kspS, "S_", KSPFGMRES, PCSHELL, 1e-6, 1e-8, 1); { PC pc; @@ -112,8 +116,12 @@ namespace AMDiS { namespace Parallel { // Create FGMRES based outer solver MSG("CREATE POS 1: %p\n", &ksp); - KSPCreate(domainComm, &ksp); + KSPCreate(domainComm, &ksp); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(ksp, getMatInterior(), getMatInterior()); +#else KSPSetOperators(ksp, getMatInterior(), getMatInterior(), SAME_NONZERO_PATTERN); +#endif if (getInfo() >= 10) KSPMonitorSet(ksp, KSPMonitorDefault, PETSC_NULL, PETSC_NULL); else if (getInfo() >= 20) diff --git a/AMDiS/src/parallel/PetscSolverFeti.cc b/AMDiS/src/parallel/PetscSolverFeti.cc index e1e81b3abd532c20224c8524d1b57fa76870818f..ef54c0621e9e36079aea14265bda8da76211613f 100644 --- a/AMDiS/src/parallel/PetscSolverFeti.cc +++ b/AMDiS/src/parallel/PetscSolverFeti.cc @@ -1050,7 +1050,11 @@ namespace AMDiS { namespace Parallel { } KSPCreate(domainComm, &ksp_schur_primal); - KSPSetOperators(ksp_schur_primal, mat_schur_primal, mat_schur_primal, SAME_NONZERO_PATTERN); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(ksp_schur_primal, mat_schur_primal, mat_schur_primal); +#else + KSPSetOperators(ksp_schur_primal, mat_schur_primal, mat_schur_primal, SAME_NONZERO_PATTERN); +#endif KSPSetOptionsPrefix(ksp_schur_primal, "schur_primal_"); KSPSetType(ksp_schur_primal, KSPGMRES); KSPSetFromOptions(ksp_schur_primal); @@ -1070,8 +1074,11 @@ namespace AMDiS { namespace Parallel { // === Create KSP solver object and set appropriate solver options. === KSPCreate(domainComm, &ksp_schur_primal); - KSPSetOperators(ksp_schur_primal, mat_schur_primal, mat_schur_primal, - SAME_NONZERO_PATTERN); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(ksp_schur_primal, mat_schur_primal, mat_schur_primal); +#else + KSPSetOperators(ksp_schur_primal, mat_schur_primal, mat_schur_primal, SAME_NONZERO_PATTERN); +#endif KSPSetOptionsPrefix(ksp_schur_primal, "schur_primal_"); KSPSetType(ksp_schur_primal, KSPPREONLY); PC pc_schur_primal; @@ -1357,7 +1364,11 @@ namespace AMDiS { namespace Parallel { } KSPCreate(domainComm, &ksp_feti); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(ksp_feti, mat_feti, mat_feti); +#else KSPSetOperators(ksp_feti, mat_feti, mat_feti, SAME_NONZERO_PATTERN); +#endif KSPSetOptionsPrefix(ksp_feti, "feti_"); KSPSetType(ksp_feti, KSPGMRES); KSPSetTolerances(ksp_feti, 0, 1e-8, 1e+3, 1000); @@ -1431,7 +1442,11 @@ namespace AMDiS { namespace Parallel { (void(*)(void))petscMultMatFetiInexact); KSPCreate(domainComm, &ksp_feti); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(ksp_feti, mat_feti, mat_feti); +#else KSPSetOperators(ksp_feti, mat_feti, mat_feti, SAME_NONZERO_PATTERN); +#endif KSPSetOptionsPrefix(ksp_feti, "feti_"); KSPSetType(ksp_feti, KSPGMRES); KSPSetTolerances(ksp_feti, 0, 1e-8, 1e+3, 1000); @@ -1448,9 +1463,11 @@ namespace AMDiS { namespace Parallel { createVec(localDofMap, fetiInexactPreconData.tmp_vec_b0); KSPCreate(domainComm, &(fetiInexactPreconData.ksp_pc_feti)); - KSPSetOperators(fetiInexactPreconData.ksp_pc_feti, - mat_lagrange, mat_lagrange, - SAME_NONZERO_PATTERN); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(fetiInexactPreconData.ksp_pc_feti, mat_lagrange, mat_lagrange); +#else + KSPSetOperators(fetiInexactPreconData.ksp_pc_feti, mat_lagrange, mat_lagrange, SAME_NONZERO_PATTERN); +#endif KSPGetPC(fetiInexactPreconData.ksp_pc_feti, &(fetiInexactPreconData.pc_feti)); createFetiPreconLumped(fetiInexactPreconData.pc_feti); @@ -1582,8 +1599,11 @@ namespace AMDiS { namespace Parallel { ("Stokes mode does not yet support the Dirichlet precondition!\n"); KSPCreate(PETSC_COMM_SELF, &ksp_interior); - KSPSetOperators(ksp_interior, mat_interior_interior, mat_interior_interior, - SAME_NONZERO_PATTERN); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(ksp_interior, mat_interior_interior, mat_interior_interior); +#else + KSPSetOperators(ksp_interior, mat_interior_interior, mat_interior_interior, SAME_NONZERO_PATTERN); +#endif KSPSetOptionsPrefix(ksp_interior, "precon_interior_"); KSPSetType(ksp_interior, KSPPREONLY); PC pc_interior; diff --git a/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.cc b/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.cc index 858f7969168f15bee374b82d26d9160fa2cd5301..cbd5d6ccf9e8d48c0be216d18d54e04af5a06cee 100644 --- a/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.cc +++ b/AMDiS/src/parallel/PetscSolverGlobalBlockMatrix.cc @@ -150,8 +150,11 @@ namespace AMDiS { namespace Parallel { FUNCNAME("PetscSolverGlobalBlockMatrix::initSolver()"); KSPCreate(domainComm, &ksp); - KSPSetOperators(ksp, getMatInterior(), getMatInterior(), - SAME_NONZERO_PATTERN); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(ksp, getMatInterior(), getMatInterior()); +#else + KSPSetOperators(ksp, getMatInterior(), getMatInterior(), SAME_NONZERO_PATTERN); +#endif KSPSetOptionsPrefix(ksp, kspPrefix.c_str()); KSPSetFromOptions(ksp); } diff --git a/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc b/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc index 5f72e8dbd75edbe47bb4a006ab680a963e70c961..6cb8273f6795b81607f4fc125e5a262e231cc89c 100644 --- a/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc +++ b/AMDiS/src/parallel/PetscSolverGlobalMatrix.cc @@ -328,8 +328,11 @@ namespace AMDiS { namespace Parallel { // === Create solver for the non primal (thus local) variables. === KSPCreate(domainComm, &kspInterior); - KSPSetOperators(kspInterior, getMatInterior(), getMatInterior(), - SAME_NONZERO_PATTERN); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(kspInterior, getMatInterior(), getMatInterior()); +#else + KSPSetOperators(kspInterior, getMatInterior(), getMatInterior(), SAME_NONZERO_PATTERN); +#endif KSPSetOptionsPrefix(kspInterior, "interior_"); KSPSetType(kspInterior, KSPPREONLY); KSPGetPC(kspInterior, &pcInterior); @@ -380,6 +383,11 @@ namespace AMDiS { namespace Parallel { } + /// 1.) set startsolution + /// 2.) create null-space + /// 3.) solve Ax=b + /// 4.) destroy null-space + /// 5.) transfer solution back to DOFVector void PetscSolverGlobalMatrix::solvePetscMatrix(SystemVector &vec, AdaptInfo *adaptInfo) { @@ -447,8 +455,11 @@ namespace AMDiS { namespace Parallel { TEST_EXIT_DBG(coarseSpaceMap.empty())("Not supported!\n"); MSG("Remove nullspace from rhs vector.\n"); - +#if (PETSC_VERSION_MINOR >= 5) + MatNullSpaceRemove(matNullspace, getVecRhsInterior()); +#else MatNullSpaceRemove(matNullspace, getVecRhsInterior(), PETSC_NULL); +#endif } } else { TEST_EXIT(removeRhsNullspace == false) @@ -601,8 +612,11 @@ namespace AMDiS { namespace Parallel { void PetscSolverGlobalMatrix::initSolver(KSP &ksp) { KSPCreate(domainComm, &ksp); - KSPSetOperators(ksp, getMatInterior(), getMatInterior(), - SAME_NONZERO_PATTERN); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(ksp, getMatInterior(), getMatInterior()); +#else + KSPSetOperators(ksp, getMatInterior(), getMatInterior(), SAME_NONZERO_PATTERN); +#endif KSPSetTolerances(ksp, 0.0, 1e-8, PETSC_DEFAULT, PETSC_DEFAULT); KSPSetType(ksp, KSPBCGS); KSPSetOptionsPrefix(ksp, kspPrefix.c_str()); @@ -632,6 +646,7 @@ namespace AMDiS { namespace Parallel { { } + /// called by \ref fillPetscMatrix void PetscSolverGlobalMatrix::setDofMatrix(DOFMatrix* seqMat, int rowComp, int colComp) { @@ -810,6 +825,7 @@ namespace AMDiS { namespace Parallel { } + /// called by \ref fillPetscRhs void PetscSolverGlobalMatrix::setDofVector(Vec vecInterior, Vec vecCoarse, DOFVector<double>* vec, diff --git a/AMDiS/src/parallel/PetscSolverNSCH.cc b/AMDiS/src/parallel/PetscSolverNSCH.cc index cbeac6299597696270afba983959053843bc337a..2e6a142edaead8ba565f31363c8b2515e72edf25 100644 --- a/AMDiS/src/parallel/PetscSolverNSCH.cc +++ b/AMDiS/src/parallel/PetscSolverNSCH.cc @@ -184,7 +184,11 @@ namespace AMDiS { namespace Parallel { // Create FGMRES based outer solver MSG("CREATE POS 1: %p\n", &ksp); KSPCreate(domainComm, &ksp); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(ksp, getMatInterior(), getMatInterior()); +#else KSPSetOperators(ksp, getMatInterior(), getMatInterior(), SAME_NONZERO_PATTERN); +#endif KSPMonitorSet(ksp, KSPMonitorTrueResidualNorm, PETSC_NULL, PETSC_NULL); petsc_helper::setSolver(ksp, "ch_", KSPFGMRES, PCSHELL, getRelative(), getTolerance(), getMaxIterations()); setConstantNullSpace(ksp, componentSpaces[0]->getMesh()->getDim() , true); @@ -333,7 +337,12 @@ namespace AMDiS { namespace Parallel { ///erstelle kspVelocity KSPCreate((meshDistributor->getMpiComm(0)), &(matShellContext.kspVelocity)); - KSPSetOperators(matShellContext.kspVelocity, matShellContext.velocityMat, matShellContext.velocityMat, SAME_NONZERO_PATTERN); + +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(matShellContext.kspVelocity, matShellContext.velocityMat, matShellContext.velocityMat); +#else + KSPSetOperators(matShellContext.kspVelocity, matShellContext.velocityMat, matShellContext.velocityMat, SAME_NONZERO_PATTERN); +#endif ///regularisiere LaplaceMatrix if (regularizeLaplace) @@ -342,7 +351,11 @@ namespace AMDiS { namespace Parallel { rows[0]=0; MatZeroRows(laplaceMatrixSolver->getMatInterior(), 1, rows, 0, PETSC_NULL, PETSC_NULL); KSPCreate((meshDistributor->getMpiComm(0)), &(matShellContext.kspLaplace)); - KSPSetOperators(matShellContext.kspLaplace, laplaceMatrixSolver->getMatInterior(), laplaceMatrixSolver->getMatInterior(), SAME_NONZERO_PATTERN); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(matShellContext.kspLaplace, laplaceMatrixSolver->getMatInterior(), laplaceMatrixSolver->getMatInterior()); +#else + KSPSetOperators(matShellContext.kspLaplace, laplaceMatrixSolver->getMatInterior(), laplaceMatrixSolver->getMatInterior(), SAME_NONZERO_PATTERN); +#endif } else { matShellContext.kspLaplace=laplaceMatrixSolver->getSolver(); diff --git a/AMDiS/src/parallel/PetscSolverNavierStokes.cc b/AMDiS/src/parallel/PetscSolverNavierStokes.cc index 6509b5f9dfe0bb62bb73b851cf5c970dda24783c..4cb7f602c7747d110f5600fce06fd3bcd9d52957 100644 --- a/AMDiS/src/parallel/PetscSolverNavierStokes.cc +++ b/AMDiS/src/parallel/PetscSolverNavierStokes.cc @@ -117,7 +117,11 @@ namespace AMDiS { namespace Parallel { MSG("CREATE POS 1: %p\n", &ksp); KSPCreate(domainComm, &ksp); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(ksp, getMatInterior(), getMatInterior()); +#else KSPSetOperators(ksp, getMatInterior(), getMatInterior(), SAME_NONZERO_PATTERN); +#endif if (getInfo() >= 10) KSPMonitorSet(ksp, KSPMonitorDefault, PETSC_NULL, PETSC_NULL); else if (getInfo() >= 20) diff --git a/AMDiS/src/parallel/PetscSolverSchur.cc b/AMDiS/src/parallel/PetscSolverSchur.cc index ea6ff64c96e178cc15e116b6d51daecd6e10e506..0713cc8ffcfd0e906498bb3de68a53795e3c945b 100644 --- a/AMDiS/src/parallel/PetscSolverSchur.cc +++ b/AMDiS/src/parallel/PetscSolverSchur.cc @@ -292,8 +292,11 @@ namespace AMDiS { namespace Parallel { KSPCreate(domainComm, &kspInterior); - KSPSetOperators(kspInterior, getMatInterior(), getMatInterior(), - SAME_NONZERO_PATTERN); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(kspInterior, getMatInterior(), getMatInterior()); +#else + KSPSetOperators(kspInterior, getMatInterior(), getMatInterior(), SAME_NONZERO_PATTERN); +#endif KSPSetTolerances(kspInterior, 0.0, 1e-8, PETSC_DEFAULT, PETSC_DEFAULT); KSPSetFromOptions(kspInterior); diff --git a/AMDiS/src/solver/BITL_Solver.h b/AMDiS/src/solver/BITL_Solver.h new file mode 100644 index 0000000000000000000000000000000000000000..bbffa4b9fd4028db9049f7bbe567e66ccd7eb83e --- /dev/null +++ b/AMDiS/src/solver/BITL_Solver.h @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * AMDiS - Adaptive multidimensional simulations + * + * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved. + * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis + * + * Authors: + * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * + * This file is part of AMDiS + * + * See also license.opensource.txt in the distribution. + * + ******************************************************************************/ + + +/** \file BITL_Solver.h */ + +#ifndef AMDIS_BITL_SOLVER_H +#define AMDIS_BITL_SOLVER_H + +#include "solver/BlockMTLMatrix.h" + +#include "solver/MTL4Solver.h" +#include "solver/ITL_Runner.h" +#include "solver/ITL_Solver.h" +#include "MTL4Types.h" + +#include "solver/itl/block_diagonal.hpp" + +namespace AMDiS { + + + /** + * \ingroup Solver + * + * \brief + * Wrapper for MTL4 itl-solvers applied to block matrices. + * + */ + template< typename SolverType > + struct BITL_Solver : MTL4Solver< BlockMTLMatrix, MTLTypes::MTLVector, ITL_Runner< SolverType, BlockMTLMatrix, MTLTypes::MTLVector > > + { + BITL_Solver(std::string name) + : MTL4Solver< BlockMTLMatrix, MTLTypes::MTLVector, ITL_Runner< SolverType, BlockMTLMatrix, MTLTypes::MTLVector > >(name) {} + }; + + // =================================================================================== + + typedef BITL_Solver< cg_solver_type > B_CGSolver; + typedef BITL_Solver< cgs_solver_type > B_CGSSolver; +// typedef BITL_Solver< bicg_solver_type > B_BiCGSolver; // uses adjoint(A) + typedef BITL_Solver< bicgstab_type > B_BiCGStabSolver; +// typedef BITL_Solver< bicgstab2_type > B_BiCGStab2Solver; // ERROR +// typedef BITL_Solver< qmr_solver_type > B_QMRSolver; // uses trans(A) + typedef BITL_Solver< tfqmr_solver_type > B_TFQMRSolver; +// typedef BITL_Solver< bicgstab_ell_type > B_BiCGStabEllSolver; // ERROR + typedef BITL_Solver< gmres_type > B_GMResSolver; +// typedef BITL_Solver< idr_s_type > B_IDRsSolver; // ERROR + typedef BITL_Solver< minres_solver_type> B_MinResSolver; + typedef BITL_Solver< gcr_type > B_GcrSolver; + typedef BITL_Solver< fgmres_type > B_FGMResSolver; + typedef BITL_Solver< preonly_type > B_PreOnly; + + // =================================================================================== + + typedef ITL_Preconditioner<itl::pc::diagonal<BlockMTLMatrix>, BlockMTLMatrix, MTLTypes::MTLVector > BlockDiagonalPreconditioner; + typedef ITL_Preconditioner<itl::pc::identity<BlockMTLMatrix>, BlockMTLMatrix, MTLTypes::MTLVector > BlockIdentityPreconditioner; + + template<typename MatrixType> + void initCreatorMap(std::string backend) + { + typedef MTL4Solver<MatrixType, MTLTypes::MTLVector, ITL_Runner<cg_solver_type, MatrixType, MTLTypes::MTLVector> > MatCgSolver; + typedef MTL4Solver<MatrixType, MTLTypes::MTLVector, ITL_Runner<cgs_solver_type, MatrixType, MTLTypes::MTLVector> > MatCgsSolver; + typedef MTL4Solver<MatrixType, MTLTypes::MTLVector, ITL_Runner<bicgstab_type, MatrixType, MTLTypes::MTLVector> > MatBicgstabSolver; + typedef MTL4Solver<MatrixType, MTLTypes::MTLVector, ITL_Runner<tfqmr_solver_type, MatrixType, MTLTypes::MTLVector> > MatTfqmrSolver; + typedef MTL4Solver<MatrixType, MTLTypes::MTLVector, ITL_Runner<gmres_type, MatrixType, MTLTypes::MTLVector> > MatGmresSolver; + typedef MTL4Solver<MatrixType, MTLTypes::MTLVector, ITL_Runner<minres_solver_type, MatrixType, MTLTypes::MTLVector> > MatMinresSolver; + typedef MTL4Solver<MatrixType, MTLTypes::MTLVector, ITL_Runner<gcr_type, MatrixType, MTLTypes::MTLVector> > MatGcrSolver; + typedef MTL4Solver<MatrixType, MTLTypes::MTLVector, ITL_Runner<preonly_type, MatrixType, MTLTypes::MTLVector> > MatPreonlySolver; + typedef MTL4Solver<MatrixType, MTLTypes::MTLVector, ITL_Runner<fgmres_type, MatrixType, MTLTypes::MTLVector> > MatFgmresSolver; + + CreatorMap<LinearSolver>::addCreator(backend + "_cg", new typename MatCgSolver::Creator); + CreatorMap<LinearSolver>::addCreator(backend + "_cgs", new typename MatCgsSolver::Creator); + CreatorMap<LinearSolver>::addCreator(backend + "_bicgstab", new typename MatBicgstabSolver::Creator); + CreatorMap<LinearSolver>::addCreator(backend + "_tfqmr", new typename MatTfqmrSolver::Creator); + CreatorMap<LinearSolver>::addCreator(backend + "_gmres", new typename MatGmresSolver::Creator); + CreatorMap<LinearSolver>::addCreator(backend + "_minres", new typename MatMinresSolver::Creator); + CreatorMap<LinearSolver>::addCreator(backend + "_gcr", new typename MatGcrSolver::Creator); + CreatorMap<LinearSolver>::addCreator(backend + "_preconly", new typename MatPreonlySolver::Creator); + CreatorMap<LinearSolver>::addCreator(backend + "_fgmres", new typename MatFgmresSolver::Creator); + } +} // namespace AMDiS + +#endif // AMDIS_BITL_SOLVER + diff --git a/AMDiS/src/solver/BlockMTLMatrix.h b/AMDiS/src/solver/BlockMTLMatrix.h new file mode 100644 index 0000000000000000000000000000000000000000..78742d5aa4a3e0bf53f6cff578f8fc2204925945 --- /dev/null +++ b/AMDiS/src/solver/BlockMTLMatrix.h @@ -0,0 +1,180 @@ +/****************************************************************************** + * + * AMDiS - Adaptive multidimensional simulations + * + * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved. + * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis + * + * Authors: + * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * + * This file is part of AMDiS + * + * See also license.opensource.txt in the distribution. + * + ******************************************************************************/ + + +/** \file BlockMTLMatrix.h */ + +#ifndef AMDIS_BLOCK_MTL_MATRIX_H +#define AMDIS_BLOCK_MTL_MATRIX_H + +#include "solver/SolverMatrix.h" +#include "solver/Mapper.h" +#include "MTL4Types.h" + +namespace AMDiS +{ + + /// A wrapper for AMDiS::SolverMatrix to be used in MTL/ITL solvers + struct BlockMTLMatrix + { + typedef typename mtl::Collection<MTLTypes::MTLMatrix>::size_type size_type; + + size_type n; // overall number of rows + size_type m; // overall number of columns + + size_t n_rows; // number of row blocks + size_t n_cols; // number of column blocks + + BlockMTLMatrix() + : A(NULL), initialized(false) + { } + + BlockMTLMatrix(const SolverMatrix<Matrix<DOFMatrix*> >& A_) + : A(&A_), initialized(false) + { + init(); + } + + void setMatrix(const SolverMatrix<Matrix<DOFMatrix*> >& A_) + { + A = &A_; + init(); + } + + void init() + { + RectangularMapper mapper(*A); + n = mapper.getNumRows(); + m = mapper.getNumCols(); + n_rows = mapper.getNumRowComponents(); + n_cols = mapper.getNumColComponents(); + + r_rows.resize(n_rows); + r_cols.resize(n_cols); + int start = 0; + mapper.setCol(0); + for (size_t i = 0; i < n_rows; i++) { + mapper.setRow(i+1); + int finish = mapper.row(0); + r_rows[i].set(start, finish); + start = finish; + } + start = 0; + mapper.setRow(0); + for (size_t i = 0; i < n_cols; i++) { + mapper.setCol(i+1); + int finish = mapper.col(0); + r_cols[i].set(start, finish); + start = finish; + } + initialized = true; + } + + inline const mtl::irange& getRowRange(size_t i) const + { + return r_rows[i]; + } + + inline const mtl::irange& getColRange(size_t i) const + { + return r_cols[i]; + } + + const DOFMatrix::base_matrix_type& getSubMatrix(size_t i, size_t j) const + { + return A->getSubMatrix(i, j); + } + + /// perform blockwise multiplication A*b -> x + template <typename VectorIn, typename VectorOut, typename Assign> + void mult(const VectorIn& b, VectorOut& x, Assign) const + { + TEST_EXIT_DBG(initialized)("Block matrix not initialized. Assign a SolverMatrix first!\n"); + + for (size_t i = 0; i < n_rows; i++) { + VectorOut x_i(x[r_rows[i]]); + bool first = true; + for (size_t j = 0; j < n_cols; j++) { + if ((*A->getOriginalMat())[i][j]) { + const VectorIn b_j(b[r_cols[j]]); + if (first) { + Assign::first_update(x_i, A->getSubMatrix(i, j) * b_j); + first = false; + } else { + Assign::update(x_i, A->getSubMatrix(i, j) * b_j); + } + } + } + } + } + + template <typename VectorIn> + mtl::vector::mat_cvec_multiplier<BlockMTLMatrix, VectorIn> operator*(const VectorIn& v) const + { return mtl::vector::mat_cvec_multiplier<BlockMTLMatrix, VectorIn>(*this, v); } + + protected: + bool initialized; + + private: + const SolverMatrix<Matrix<DOFMatrix*> >* A; + std::vector<mtl::irange> r_rows, r_cols; + }; + + namespace dispatch + { + template< typename M > + void initMatrix(BlockMTLMatrix& m, MapperBase<M>& mapper) + { } + + template< typename M > + void fillMatrix(BlockMTLMatrix& m, const SolverMatrix<Matrix<DOFMatrix*> >& source, MapperBase<M>& mapper) + { + m.setMatrix(source); + } + + } // end namespace dispatch + +} // end namespace AMDiS + + +inline AMDiS::BlockMTLMatrix::size_type size(const AMDiS::BlockMTLMatrix& A) { return (A.n) * (A.m); } +inline AMDiS::BlockMTLMatrix::size_type num_rows(const AMDiS::BlockMTLMatrix& A) { return A.n; } +inline AMDiS::BlockMTLMatrix::size_type num_cols(const AMDiS::BlockMTLMatrix& A) { return A.m; } + +namespace mtl +{ + template <> + struct Collection<AMDiS::BlockMTLMatrix> + { + typedef double value_type; + typedef int size_type; + }; + + namespace ashape + { + template <> struct ashape_aux<AMDiS::BlockMTLMatrix> + { + typedef nonscal type; + }; + } // end namespace ashape + +} // end namespace mtl + +#endif // AMDIS_BLOCK_MTL_MATRIX_H \ No newline at end of file diff --git a/AMDiS/src/solver/BlockPreconditioner.h b/AMDiS/src/solver/BlockPreconditioner.h new file mode 100644 index 0000000000000000000000000000000000000000..ec00bdda149b42bfde38e444afab42375bb056e7 --- /dev/null +++ b/AMDiS/src/solver/BlockPreconditioner.h @@ -0,0 +1,134 @@ +/****************************************************************************** + * + * AMDiS - Adaptive multidimensional simulations + * + * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved. + * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis + * + * Authors: + * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * + * This file is part of AMDiS + * + * See also license.opensource.txt in the distribution. + * + ******************************************************************************/ + + +/** \file BlockPreconditioner.h */ + +#ifndef AMDIS_BLOCK_PRECONDITIONER_H +#define AMDIS_BLOCK_PRECONDITIONER_H + +#include "solver/ITL_Preconditioner.h" +#include "solver/SolverMatrix.h" + +namespace AMDiS { + + /// Basis preconditioner structure for block-preconditioners + template<typename MatrixType> + struct BlockPreconditioner : ITL_BasePreconditioner<MatrixType, MTLTypes::MTLVector> + { + typedef SolverMatrix<Matrix<DOFMatrix*> > BlockMatrix; + typedef ITL_BasePreconditioner<MatrixType, MTLTypes::MTLVector> super; + typedef BlockPreconditioner<MatrixType> self; + + BlockPreconditioner() + : A(NULL), fullMatrix(NULL) + { } + + virtual ~BlockPreconditioner() {} + + /// extract iranges from BlockMatrix to be used to extract sub-vectors and sub-matrices. + void init(const SolverMatrix<Matrix<DOFMatrix*> >& A_, const MatrixType& fullMatrix_) override + { + A = &A_; + fullMatrix = &fullMatrix_; + + BlockMapper mapper(A_); + rows.resize(mapper.getNumComponents()); + int start = 0; + for (int i = 0; i < mapper.getNumComponents(); i++) { + mapper.setRow(i+1); + int finish = mapper.row(0); + rows[i].set(start, finish); + start = finish; + } + } + + virtual void solve(const MTLTypes::MTLVector& b, MTLTypes::MTLVector& x) const + { FUNCNAME("BlockPreconditioner::solve()"); + TEST_EXIT(false)("Must be implemented in derived classes!\n"); + } + + virtual void adjoint_solve(const MTLTypes::MTLVector& x, MTLTypes::MTLVector& y) const + { FUNCNAME("BlockPreconditioner::adjoint_solve()"); + TEST_EXIT(false)("Must be implemented in derived classes!\n"); + } + + inline const mtl::irange& getRowRange(size_t i) const + { + return rows[i]; + } + + inline const mtl::irange& getColRange(size_t i) const + { + return rows[i]; + } + + const DOFMatrix::base_matrix_type& getSubMatrix(size_t i, size_t j) const + { + return A->getSubMatrix(i, j); + } + + template<typename SolverType, typename RunnerType> + static void createSubSolver(std::string param, SolverType*& solver, RunnerType*& runner, std::string solverType = "0") + { + // definition of standard-backends +#if defined HAVE_PARALLEL_PETSC + std::string backend("p_petsc"); +#elif defined HAVE_PARALLEL_MTL + std::string backend("p_mtl"); +#elif defined HAVE_PETSC + std::string backend("petsc"); +#else + std::string backend("mtl"); +#endif + + // === read backend-name === + std::string initFileStr = param + "->solver"; + Parameters::get(initFileStr + "->backend", backend); + + // === read solver-name === + Parameters::get(initFileStr, solverType); + + if (backend != "0" && backend != "no" && backend != "") + solverType = backend + "_" + solverType; + + LinearSolverCreator *solverCreator = + dynamic_cast<LinearSolverCreator*>(CreatorMap<LinearSolver>::getCreator(solverType, initFileStr)); + TEST_EXIT(solverCreator) + ("No valid solver type found in parameter \"%s\"\n", initFileStr.c_str()); + solverCreator->setName(initFileStr); + solver = dynamic_cast<SolverType*>(solverCreator->create()); + assert(solver != NULL); + + runner = dynamic_cast<RunnerType*>(solver->getRunner()); + assert(runner != NULL); + } + + + protected: + const SolverMatrix<Matrix<DOFMatrix*> >* A; + const MatrixType* fullMatrix; + + std::vector<mtl::irange> rows; + }; + +} // end namespace AMDiS + +#endif // AMDIS_BLOCK_PRECONDITIONER_H diff --git a/AMDiS/src/solver/CombinedPreconditioner.h b/AMDiS/src/solver/CombinedPreconditioner.h new file mode 100644 index 0000000000000000000000000000000000000000..43e0ef7ba544f70f3dbfdb93b37a70c41eb34787 --- /dev/null +++ b/AMDiS/src/solver/CombinedPreconditioner.h @@ -0,0 +1,153 @@ +/****************************************************************************** + * + * AMDiS - Adaptive multidimensional simulations + * + * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved. + * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis + * + * Authors: + * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * + * This file is part of AMDiS + * + * See also license.opensource.txt in the distribution. + * + ******************************************************************************/ + + +/** \file CombinedPreconditioner.h */ + +#ifndef AMDIS_COMBINED_PRECONDITIONER_H +#define AMDIS_COMBINED_PRECONDITIONER_H + +#include "solver/BlockPreconditioner.h" + +namespace AMDiS { + + /// preconditioner structure that combines various block-preconditioners + template<typename MatrixType> + struct CombinedPreconditioner : BlockPreconditioner<MatrixType> + { + typedef BlockPreconditioner<MatrixType> super; + typedef ITL_BasePreconditioner<MatrixType, MTLTypes::MTLVector> precon_base; + typedef CombinedPreconditioner<MatrixType> self; + + class Creator : public CreatorInterfaceName<precon_base> + { + public: + Creator(int l0) + { l.push_back(l0); }; + + Creator(int l0, int l1) + { l.push_back(l0); l.push_back(l1); }; + + Creator(int l0, int l1, int l2) + { l.push_back(l0); l.push_back(l1); l.push_back(l2); }; + + Creator(const std::vector<int>& l) : l(l) {} + + virtual ~Creator() {} + + precon_base* create() { + return new self(l); + } + private: + std::vector<int> l; + }; + + /// Constructor + CombinedPreconditioner(const std::vector<int>& parts_) + : super(), parts(parts_) + { + precon.resize(parts.size(), &identity); + subA.resize(parts.size()); + } + + virtual ~CombinedPreconditioner() {} + + /// Extract iranges from SolverMatrix to be used to extract sub-vectors and sub-matrices. + void init(const SolverMatrix<Matrix<DOFMatrix*> >& A_, const MatrixType& fullMatrix_) override + { + super::A = &A_; + super::fullMatrix = &fullMatrix_; + + BlockMapper mapper(A_); + rows.resize(mapper.getNumComponents()); + int start = 0; + int sum = 0; + for (int p = 0; p < parts.size(); p++) { + sum += parts[p]; + if (sum > mapper.getNumComponents()) + throw std::runtime_error("range out of bound!"); + mapper.setRow(sum); + int finish = mapper.row(0); + if (finish <= start) + throw std::runtime_error("ranges overlap!"); + rows[p].set(start, finish); + start = finish; + } + + const Matrix<DOFMatrix*>& mat = *A_.getOriginalMat(); + sum = 0; + for (int p = 0; p < parts.size(); p++) { + Matrix<DOFMatrix*>* subMat = new Matrix<DOFMatrix*>(parts[p],parts[p]); + for (int i = 0; i < parts[p]; i++) + for (int j = 0; j < parts[p]; j++) + (*subMat)[i][j] = mat[i+sum][j+sum]; + subA[p].setMatrix(*subMat); + precon[p]->init(subA[p], fullMatrix_); + } + } + + void exit() override + { + for (int p = 0; p < parts.size(); p++) { + precon[p]->exit(); + delete subA[p].getOriginalMat(); + } + } + + + /// Apply the preconditioners block-wise + /** + * solve Px = b, with + * P = diag(P1, P2, ...) + **/ + void solve(const MTLTypes::MTLVector& b, MTLTypes::MTLVector& x) const override + { FUNCNAME("CombinedPreconditioner::solve()"); + + x.change_dim(num_rows(b)); + + for (size_t i = 0; i < precon.size(); i++) { + const MTLTypes::MTLVector b_i(b[rows[i]]); + MTLTypes::MTLVector x_i(x[rows[i]]); + precon[i]->solve(b_i, x_i); + } + } + + /// Sets a preconditioner for part i. If non is set, an identity preconditioner is used. + void setPreconditioner(size_t i, precon_base& p) + { + precon[i] = &p; + } + + protected: + std::vector<mtl::irange> rows; + + // length of blocks assigned to a seperate preconditioners + std::vector<int> parts; + + std::vector<precon_base*> precon; + std::vector<SolverMatrix<Matrix<DOFMatrix*> > > subA; + + DOFMatrix::base_matrix_type dummy; + ITL_Preconditioner<itl::pc::identity<MatrixType>, MatrixType, MTLTypes::MTLVector > identity; + }; + +} // end namespace AMDiS + +#endif // AMDIS_COMBINED_PRECONDITIONER_H diff --git a/AMDiS/src/solver/ITL_Preconditioner.h b/AMDiS/src/solver/ITL_Preconditioner.h index ca048c12a116d27bb2989259bf039591e7df487a..8106043d1241acbae4f07e0cd0ebccb2731ca8f6 100644 --- a/AMDiS/src/solver/ITL_Preconditioner.h +++ b/AMDiS/src/solver/ITL_Preconditioner.h @@ -51,8 +51,7 @@ namespace AMDiS { virtual ~ITL_BasePreconditioner() {} - typedef SolverMatrix<Matrix<DOFMatrix*> > BlockMatrix; - virtual void init(const BlockMatrix& A, const MatrixType& fullMatrix) = 0; + virtual void init(const SolverMatrix<Matrix<DOFMatrix*> >& A, const MatrixType& fullMatrix) = 0; virtual void solve(const VectorType& x, VectorType& y) const = 0; virtual void adjoint_solve(const VectorType& x, VectorType& y) const = 0; }; diff --git a/AMDiS/src/solver/ITL_Runner.h b/AMDiS/src/solver/ITL_Runner.h index aa1216da9542b93f32f5de56d2578d07f57452de..036198a39683be007ab6af4215cf4710c0eaeee4 100644 --- a/AMDiS/src/solver/ITL_Runner.h +++ b/AMDiS/src/solver/ITL_Runner.h @@ -82,7 +82,7 @@ namespace AMDiS { /// Implementation of \ref MTL4Runner::init() - void init(const typename super::BlockMatrix& A, const MatrixType& fullMatrix) override + void init(const SolverMatrix<Matrix<DOFMatrix*> >& A, const MatrixType& fullMatrix) override { preconPair.l->init(A, fullMatrix); preconPair.r->init(A, fullMatrix); @@ -209,7 +209,7 @@ namespace AMDiS { leftCreator = dynamic_cast<CreatorInterfaceName< ITL_BasePreconditioner<MatrixType, VectorType> >*>( CreatorMap<ITL_BasePreconditioner<MatrixType, VectorType> >::getCreator(preconType, initFileStr) ); TEST_EXIT(leftCreator != nullptr) - ("there is no creator for the given left preconditioner\n"); + ("There is no creator for the given left preconditioner '%s'\n", preconType.c_str()); leftCreator->setName(initFileStr); preconType = "no"; @@ -218,7 +218,7 @@ namespace AMDiS { rightCreator = dynamic_cast<CreatorInterfaceName< ITL_BasePreconditioner<MatrixType, VectorType> >*>( CreatorMap<ITL_BasePreconditioner<MatrixType, VectorType> >::getCreator(preconType, initFileStr) ); TEST_EXIT(rightCreator != nullptr) - ("there is no creator for the given right preconditioner\n"); + ("There is no creator for the given right preconditioner '%s'\n", preconType.c_str()); rightCreator->setName(initFileStr); pair.l = leftCreator->create(); diff --git a/AMDiS/src/solver/KrylovPreconditioner.h b/AMDiS/src/solver/KrylovPreconditioner.h index 8c573d2f87f13e90eb28de18935f2d2d7a7c704f..53bec1dd52ae0b3dffac545cc82db1c8735289bb 100644 --- a/AMDiS/src/solver/KrylovPreconditioner.h +++ b/AMDiS/src/solver/KrylovPreconditioner.h @@ -105,7 +105,7 @@ namespace AMDiS { } /// Implementation of \ref ITL_BasePreconditioner::init() - void init(const typename super::BlockMatrix& A, const MatrixType& fullMatrix_) override + void init(const SolverMatrix<Matrix<DOFMatrix*> >& A, const MatrixType& fullMatrix_) override { fullMatrix = &fullMatrix_; runner->init(A, fullMatrix_); diff --git a/AMDiS/src/solver/LinearSolver.h b/AMDiS/src/solver/LinearSolver.h index bfd1b1cae095095a11a5e9fd848fb4923760793e..e3f3e8924a884983ae5fafe7c52fe3d4937d54c1 100644 --- a/AMDiS/src/solver/LinearSolver.h +++ b/AMDiS/src/solver/LinearSolver.h @@ -123,9 +123,6 @@ namespace AMDiS { rel_residual = -1.0; int error_code = solveLinearSystem(A, x, b, createMatrixData, storeMatrixData); - TEST_EXIT(error_code == 0) - ("Error [%d] in LinearSolver. residual = %e, rel_residual = %e\n", error_code, residual, rel_residual); - // calculate and print resiual if (info > 0) { if (residual >= 0.0 && rel_residual >= 0.0) { diff --git a/AMDiS/src/solver/MTL4Solver.h b/AMDiS/src/solver/MTL4Solver.h index 0917b36cd016d39bda407ae46676b4b515f31944..518604b59a1cd02846f2b83888e55400e505d346 100644 --- a/AMDiS/src/solver/MTL4Solver.h +++ b/AMDiS/src/solver/MTL4Solver.h @@ -35,39 +35,80 @@ namespace AMDiS { template< typename MatrixType, typename VectorType > struct MTL4Runner : public OEMRunner { - typedef SolverMatrix<Matrix<DOFMatrix*> > BlockMatrix; +// typedef SolverMatrix<Matrix<DOFMatrix*> > BlockMatrix; + + virtual void init(const SolverMatrix<Matrix<DOFMatrix*> >& A, const MatrixType& fullMatrix) = 0; - virtual void init(const BlockMatrix& A, const MatrixType& fullMatrix) = 0; virtual int solve(const MatrixType& A, VectorType& x, const VectorType& b) = 0; - virtual int adjoint_solve(const MatrixType& A, VectorType& x, const VectorType& b) { + + virtual int adjoint_solve(const MatrixType& A, VectorType& x, const VectorType& b) + { FUNCNAME("MTL4Runner::adjoint_solve()"); ERROR_EXIT("Must be implemented in derived class!\n"); return 0; - }; + } }; -#ifndef HAVE_PARALLEL_DOMAIN_AMDIS - namespace Parallel { - typedef LinearSolver ParallelSolver; - } - typedef BlockMapper ParallelMapper; -#endif - - using Parallel::ParallelSolver; - /// Wrapper for template-argument dependent constructors - template <bool parallel = false> - struct MTL4SolverBase : LinearSolver + template < typename MatrixType, typename Enable = void> + struct MTL4SolverBase : public LinearSolver { - MTL4SolverBase(std::string name) : LinearSolver(name) {} + typedef BlockMapper Mapper; + + MTL4SolverBase(std::string name) + : LinearSolver(name) {} + + MatrixType& getMatrix() + { + return matrix; + } + + /// create a sequential BlockMapper + void initMapper(const SolverMatrix<Matrix<DOFMatrix*> >& A) + { + mapper = new BlockMapper(A); + } + + void exitMapper() + { + delete mapper; + } + + protected: + MatrixType matrix; + Mapper* mapper; }; -#ifdef HAVE_PARALLEL_DOMAIN_AMDIS - template <> - struct MTL4SolverBase<true> : ParallelSolver +#ifdef HAVE_PARALLEL_MTL4 + template < typename MatrixType > + struct MTL4SolverBase<MatrixType, typename boost::enable_if<mtl::traits::is_distributed<MatrixType> > > + : public ParallelSolver { - MTL4SolverBase(std::string name) : ParallelSolver(name, false) {} + typedef ParallelMapper Mapper; + + MTL4SolverBase(std::string name) + : ParallelSolver(name, false) {} + + MatrixType& getMatrix() + { + return matrix; + } + + /// create a parallel mapper based on local-to-global mapping + void initMapper(const SolverMatrix<Matrix<DOFMatrix*> >& A) + { + mapper = new ParallelMapper(*ParallelSolver::getDofMapping()); + } + + void exitMapper() + { + delete mapper; + } + + protected: + MatrixType matrix; + Mapper* mapper; }; #endif @@ -80,18 +121,15 @@ namespace AMDiS { * solvers where MTL4 provides an interface, can be assigned * by different Runner objects. **/ - template < typename MatrixType, typename VectorType, typename Runner, bool parallel = false/*mtl::traits::is_distributed<MatrixType>::value*/ > - class MTL4Solver : public MTL4SolverBase<parallel> + template < typename MatrixType, typename VectorType, typename Runner > + class MTL4Solver : public MTL4SolverBase<MatrixType> { private: - typedef MTL4SolverBase<parallel> super; - typedef MTL4Solver<MatrixType, VectorType, Runner> self; - - typedef typename boost::mpl::if_c<parallel, ParallelMapper, BlockMapper>::type Mapper; + typedef MTL4SolverBase<MatrixType> super; + typedef MTL4Solver<MatrixType, VectorType, Runner> self; + typedef typename super::Mapper Mapper; Runner runner; // redirect the implementation to a runner - MatrixType matrix; - Mapper* mapper; public: /// Creator class used in the LinearSolverMap. @@ -109,8 +147,8 @@ namespace AMDiS { /// Constructor MTL4Solver(std::string n) - : super(n), - runner(this) + : super(n), + runner(this) {} @@ -135,93 +173,63 @@ namespace AMDiS { } protected: - /// create a sequential BlockMapper - template<bool par> - void initMapper(const SolverMatrix<Matrix<DOFMatrix*> >& A) - { - mapper = new BlockMapper(A); - } - -#ifdef HAVE_PARALLEL_MTL4 - /// create a parallel mapper based on local-to-global mapping - template<> - void initMapper<true>(const SolverMatrix<Matrix<DOFMatrix*> >& A) - { - mapper = new ParallelMapper(*ParallelSolver::getDofMapping()); - } -#endif /// Implementation of \ref LinearSolver::solveLinearSystem() int solveLinearSystem(const SolverMatrix<Matrix<DOFMatrix*> >& A, - SystemVector& x, - SystemVector& b, - bool createMatrixData, - bool storeMatrixData) override + SystemVector& x, + SystemVector& b, + bool createMatrixData, + bool storeMatrixData) override { #ifdef HAVE_PARALLEL_DOMAIN_AMDIS MPI::COMM_WORLD.Barrier(); #endif - initMapper<parallel>(A); + super::initMapper(A); Timer t; if (createMatrixData) { - initMatrix(matrix, A, *mapper); - runner.init(A, matrix); + initMatrix(super::matrix, A, *super::mapper); + runner.init(A, super::matrix); } VectorType mtl_x; - initVector(mtl_x, x, *mapper); + initVector(mtl_x, x, *super::mapper); VectorType mtl_b; - initVector(mtl_b, b, *mapper); + initVector(mtl_b, b, *super::mapper); INFO(self::getInfo(), 8)("fill MTL4 matrix needed %.5f seconds\n", t.elapsed()); - int error = runner.solve(matrix ,mtl_x, mtl_b); - VecMap< SystemVector, Mapper > xVecMap(x, *mapper); + int error = runner.solve(super::matrix ,mtl_x, mtl_b); + + VecMap<SystemVector, Mapper> xVecMap(x, *super::mapper); mtl_x >> xVecMap; if (!storeMatrixData) runner.exit(); - delete mapper; + super::exitMapper(); return error; } // functions to initialize mtl-matrix and mtl-vector // from AMDiS matrix / vectors using mappers - /// initialize a MTL matrix - template< typename MatrixT, typename M > - void initMatrix(MatrixT& m, MapperBase<M>& mapper) - { - dispatch::initMatrix(m, mapper.self(), typename traits::distributed_tag<MatrixT>::type() ); - } - /// initialize a MTL matrix and assign values from an AMDiS matrix template< typename Matrix1, typename Matrix2, typename M > void initMatrix(Matrix1& target, const Matrix2& source, MapperBase<M>& mapper) { - dispatch::initMatrix(target, mapper.self(), typename traits::distributed_tag<Matrix1>::type() ); - MatMap< const Matrix2, M > matMap(source, mapper.self()); - target << matMap; - } - - /// initialize a MTL vector - template< typename VectorT > - void initVector(VectorT& v) - { - dispatch::initVector(v, matrix, typename traits::distributed_tag<VectorT>::type() ); - } + dispatch::initMatrix(target, mapper.self()); + dispatch::fillMatrix(target, source, mapper.self()); + } /// initialize a MTL vector and assign values from an AMDiS vector template< typename Vector1, typename Vector2, typename M > void initVector(Vector1& target, const Vector2& source, MapperBase<M>& mapper) { - initVector(target); - VecMap< const Vector2, M > srcVecMap(source, mapper.self()); - target << srcVecMap; + dispatch::initVector(target, super::matrix); + dispatch::fillVector(target, source, mapper.self()); } }; } diff --git a/AMDiS/src/solver/MTL4SolverBase.h b/AMDiS/src/solver/MTL4SolverBase.h index 51616e584d8d48db042a38896b403826bc747259..198534537a83e73d7ea07151f8680b7ef9900c9b 100644 --- a/AMDiS/src/solver/MTL4SolverBase.h +++ b/AMDiS/src/solver/MTL4SolverBase.h @@ -54,21 +54,35 @@ namespace AMDiS { namespace dispatch { + /// init matrix + template< typename MatrixOut, typename M > + void initMatrix(MatrixOut& m, MapperBase<M>& mapper) {} + + /// init vector + template< typename VectorOut, typename MatrixT > + void initVector(VectorOut& v, const MatrixT& source) {} + /// init systemmatrix depending on Mapper parameters. - template< typename MatrixT, typename M > - void initMatrix(MatrixT& m, MapperBase<M>& mapper, tag::non_distributed) + template< typename M > + void initMatrix(MTLTypes::MTLMatrix& m, MapperBase<M>& mapper) { m.change_dim(mapper.getNumRows(), mapper.getNumCols()); set_to_zero(m); } - + + template< typename MatrixOut, typename MatrixIn, typename M > + void fillMatrix(MatrixOut& m, const MatrixIn& source, MapperBase<M>& mapper) + { + MatMap< const MatrixIn, M > matMap(source, mapper.self()); + m << matMap; + } #ifdef HAVE_PARALLEL_MTL4 /// init systemmatrix depending on Mapper parameters, /// specialized for distributed matrices - template< typename MatrixT > - void initMatrix(MatrixT& m, ParallelMapper& mapper, tag::distributed) + template< typename M > + void initMatrix(MTLTypes::PMTLMatrix& m, MapperBase<M>& mapper) { mtl::par::block_distribution dist(mapper.getNumRows()); dist.setup_from_local_size(mapper.getMap().getLocalDofs()); @@ -76,27 +90,35 @@ namespace AMDiS { m.init_distribution(dist, dist, mapper.getNumRows(), mapper.getNumRows()); set_to_zero(m); } + + /// init MTL-vector depending on Mapper parameters, + /// specialized for distributed matrices + template< typename MatrixT > + void initVector(MTLTypes::PMTLVector& v, const MatrixT& matrix) + { + v.init_distribution(row_distribution(matrix), num_rows(matrix)); + set_to_zero(v); + } #endif - /// init MTL-vector depending on Mapper parameters. - template< typename VectorT, typename MatrixT > - void initVector(VectorT& v, const MatrixT& matrix, tag::non_distributed) + template< typename MatrixT > + void initVector(MTLTypes::MTLVector& v, const MatrixT& matrix) { v.change_dim(num_rows(matrix)); set_to_zero(v); } - - /// init MTL-vector depending on Mapper parameters, - /// specialized for distributed matrices - template< typename VectorT, typename MatrixT > - void initVector(VectorT& v, const MatrixT& matrix, tag::distributed) + /// fill MTL-vector + template< typename VectorOut, typename VectorIn, typename M > + void fillVector(VectorOut& v, const VectorIn& source, MapperBase<M>& mapper) { - v.init_distribution(row_distribution(matrix), num_rows(matrix)); - set_to_zero(v); + VecMap< const VectorIn, M > srcVecMap(source, mapper.self()); + v << srcVecMap; } + + } // end namespace dispatch } // end namespace AMDiS diff --git a/AMDiS/src/solver/Mapper.h b/AMDiS/src/solver/Mapper.h index 22f1a7906d84589ddb78ab54e9928efa54a7a85b..960f6b7816bf4533785a2b8ea29c7c13552f5fda 100644 --- a/AMDiS/src/solver/Mapper.h +++ b/AMDiS/src/solver/Mapper.h @@ -61,6 +61,9 @@ namespace AMDiS { /// return overall number of columns inline size_type getNumCols() const { return self().getNumCols(); } + + inline size_type getNumRows(unsigned int comp) const { return self().getNumRows(comp); } + inline size_type getNumCols(unsigned int comp) const { return self().getNumCols(comp); } /// return number of components/blocks inline unsigned int getNumComponents() const { return self().getNumComponents(); } @@ -146,6 +149,9 @@ namespace AMDiS { inline size_type getNumRows() const { return nrow; } inline size_type getNumCols() const { return ncol; } + inline size_type getNumRows(unsigned int comp) const { return sizes[comp]; } + inline size_type getNumCols(unsigned int comp) const { return sizes[comp]; } + inline unsigned int getNumComponents() const { return nComp; } private: // methods @@ -169,6 +175,86 @@ namespace AMDiS { std::vector< size_type > sizes; }; + + + + + /// Mapper implementation for non-parallel rectangular block matrices + struct RectangularMapper : public MapperBase< RectangularMapper > + { + typedef unsigned int size_type; + + /// Constructor for block-matrices + RectangularMapper(const SolverMatrix<Matrix<DOFMatrix* > >& sm ) + : nRowComp(sm.getOriginalMat()->getNumRows()), + nColComp(sm.getOriginalMat()->getNumCols()), + rowOffset(0), colOffset(0), nrow(0), ncol(0), + sizes_rows(nRowComp), sizes_cols(nColComp) + { + const Matrix<DOFMatrix* >& orMat(*sm.getOriginalMat()); + + for (int i= 0; i < nRowComp; i++) { + for (int j = 0; j < nColComp; j++) { + if (orMat[i][j]) { + sizes_rows[i] = orMat[i][j]->getRowFeSpace()->getAdmin()->getUsedSize(); + sizes_cols[j] = orMat[i][j]->getColFeSpace()->getAdmin()->getUsedSize(); + } + } + nrow += sizes_rows[i]; + } + for (int j = 0; j < nColComp; j++) + ncol += sizes_cols[j]; + } + + /// calculate row offset for row component \param r + inline void setRow( unsigned int r) + { + assert( r <= sizes_rows.size() ); + rowOffset = sum(r, sizes_rows); + } + + /// calculate column offset for col component \param c + inline void setCol( unsigned int c) + { + assert( c <= sizes_cols.size() ); + colOffset = sum(c, sizes_cols); + } + + inline size_type row(size_type r) const { return r + rowOffset; } + inline size_type col(size_type c) const { return c + colOffset; } + + inline size_type getNumRows() const { return nrow; } + inline size_type getNumCols() const { return ncol; } + + inline size_type getNumRows(unsigned int comp) const { return sizes_rows[comp]; } + inline size_type getNumCols(unsigned int comp) const { return sizes_cols[comp]; } + + inline unsigned int getNumComponents() const { return nRowComp; } + inline unsigned int getNumRowComponents() const { return nRowComp; } + inline unsigned int getNumColComponents() const { return nColComp; } + + private: // methods + + ///compute the sum of sizes from [0, end) + inline size_type sum(unsigned int end, std::vector< size_type >& sizes) const + { + unsigned int ret(0); + for (unsigned int i(0); i < end; ++i) + ret += sizes[i]; + return ret; + } + + private: // variables + + unsigned int nRowComp, nColComp; + size_type rowOffset; + size_type colOffset; + unsigned int nrow; + unsigned int ncol; + + std::vector< size_type > sizes_rows; + std::vector< size_type > sizes_cols; + }; } #endif // AMDIS_MAPPER_H diff --git a/AMDiS/src/solver/MatrixStreams.h b/AMDiS/src/solver/MatrixStreams.h index 2d43dc870ca722720a2614bf5797c400973d16b9..1193da9f6ae5add2c75f67f8039814f199337356 100644 --- a/AMDiS/src/solver/MatrixStreams.h +++ b/AMDiS/src/solver/MatrixStreams.h @@ -30,13 +30,6 @@ #include "traits/inserter.h" #include "traits/category.hpp" -#ifdef HAVE_SEQ_PETSC -#include "solver/PetscTypes.h" -#include <petsc.h> -#include <petscmat.h> -#include <petscvec.h> -#endif - namespace AMDiS { using namespace mtl::operations; @@ -181,268 +174,5 @@ namespace AMDiS { dest >> swap; } } - -#ifdef HAVE_SEQ_PETSC - - /// fill PETSc matrix from DOFMatrix - inline void operator<<(Mat& mat, const DOFMatrix& rhs) - { - bool initMatrix = false; - if (mat == PETSC_NULL) { - std::vector<PetscInt> nnz(rhs.getSize()); - for (size_t k = 0; k < static_cast<size_t>(rhs.getSize()); k++) - nnz[k] = rhs.getBaseMatrix().nnz_local(k); - - MatCreateSeqAIJ(PETSC_COMM_SELF, num_rows(rhs.getBaseMatrix()), num_cols(rhs.getBaseMatrix()), 0, &(nnz[0]), &mat); - initMatrix = true; - } - - std::vector<PetscInt> indices; - for (size_t i = 0; i < rhs.getBaseMatrix().ref_minor().size(); i++) - indices.push_back(rhs.getBaseMatrix().ref_minor()[i]); - - for (PetscInt i = 0; i < static_cast<PetscInt>(num_rows(rhs.getBaseMatrix())); i++) { - if (rhs.getBaseMatrix().nnz_local(i) > 0) - MatSetValues(mat, 1, &i, rhs.getBaseMatrix().nnz_local(i), - &(indices[rhs.getBaseMatrix().ref_major()[i]]), - &(rhs.getBaseMatrix().value_from_offset(rhs.getBaseMatrix().ref_major()[i])), ADD_VALUES); - } - - if (initMatrix) { - MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY); - MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY); - } - } - - - /// create and fill \ref PetscMatrix - inline void operator<<(PetscMatrix& mat, const SolverMatrix<Matrix<DOFMatrix*> >& Asolver) - { - if (mat.assembled) - mat.destroy(); - - const Matrix< DOFMatrix* >& A = *(Asolver.getOriginalMat()); - if (mat.isNested) { - - std::vector<PetscInt> nnz; - mat.nestMat.resize(A.getNumRows() * A.getNumCols()); - - for (size_t i = 0; i < static_cast<size_t>(A.getNumRows()); i++) { - for (size_t j = 0; j < static_cast<size_t>(A.getNumCols()); j++) { - size_t idx = i * A.getNumCols() + j; - - if (A[i][j] == nullptr - || num_rows(A[i][j]->getBaseMatrix()) == 0 - || num_cols(A[i][j]->getBaseMatrix()) == 0 - || A[i][j]->getBaseMatrix().nnz() == 0) { - mat.nestMat[idx] = PETSC_NULL; - continue; - } - - mat.nestMat[idx] << *(A[i][j]); - } - } - - // create nested matrix from a vector of block matrices - MatCreateNest(PETSC_COMM_SELF, A.getNumRows(), PETSC_NULL, A.getNumCols(), PETSC_NULL, &(mat.nestMat[0]), &mat.matrix); - } else { - bool initMatrix = false; - unsigned nRows(0); - unsigned nEntries(0); - std::vector< int > nRowsBlock(A.getNumRows()); - for(int i(0); i < A.getNumRows(); ++i) { - int j(0); - for( ; j<A.getNumCols() && A[i][j] == NULL; ++j) ; - if( j == A.getNumCols() ) { - std::stringstream ss; ss << "ERROR: solver matrix has empty row " << i << "\n"; - throw std::runtime_error(ss.str()); - } - nRowsBlock[i]=num_rows(A[i][j]->getBaseMatrix()); - nRows+=nRowsBlock[i]; - } - std::vector<PetscInt> nnz(nRows); - //initialize the nnz (could be avoided, but gets complicated - for (int i(0); i < nRows; ++i) nnz[i] = 0; - - //build a list of pairs (col, value) for each row - std::vector< std::list< std::pair<int, double > > > rowData(nRows); - //use the standard mapper to build global structure - BlockMapper mapper(Asolver); - PetscInt maxNnz(0); - for (int i(0); i < A.getNumRows(); ++i) { - mapper.setRow(i); - //compute the number of nonzeros per global row - for (int j(0); j < A.getNumCols(); ++j) { - if (A[i][j] != NULL) { - mapper.setCol(j); - const DOFMatrix::base_matrix_type& mtlMat(A[i][j]->getBaseMatrix()); - for (unsigned k(0); k < nRowsBlock[i]; ++k) { - unsigned curRow(mapper.row(k)); - nnz[curRow] += mtlMat.nnz_local(k); - maxNnz = std::max(maxNnz, nnz[curRow]); - unsigned curPos(mtlMat.ref_major()[k]); - for(unsigned l(0); l < mtlMat.nnz_local(k); ++l, ++curPos) { - rowData[curRow].push_back(std::make_pair(mapper.col(mtlMat.ref_minor()[curPos]), mtlMat.data[curPos])); - } - } - } - } - - } - if (mat.matrix == PETSC_NULL) { - MatCreateSeqAIJ(PETSC_COMM_SELF, nRows, nRows, 0, &(nnz[0]), &mat.matrix); - initMatrix = true; - } - //reduce mallocs.. - std::vector< PetscInt > colIndices(maxNnz); - std::vector< PetscScalar > values(maxNnz); - std::list< std::pair< int, double > >::iterator it; - unsigned j; - for (PetscInt i(0); i < nRows; ++i) { - j=0; it = rowData[i].begin(); - for (; it != rowData[i].end(); ++it, ++j) { - colIndices[j] = it->first; - values[j] = it->second; - } - MatSetValues(mat.matrix, 1, &i, nnz[i], &colIndices[0], &values[0], INSERT_VALUES); - } - if (initMatrix) { - MatAssemblyBegin(mat.matrix, MAT_FINAL_ASSEMBLY); - MatAssemblyEnd(mat.matrix, MAT_FINAL_ASSEMBLY); - } - } - mat.assembled = true; - } - - - /// fill PETSc vector from DOFVector - inline void operator<<(Vec& petscVec, const DOFVector<double>& vec) - { - // Traverse all used DOFs in the dof vector. - DOFConstIterator<double> dofIt(&vec, USED_DOFS); - PetscInt index = 0; - for (dofIt.reset(); !dofIt.end(); ++dofIt, ++index) { - double value = *dofIt; - VecSetValue(petscVec, index, value, ADD_VALUES); - } - } - - - /// DOFVector from PETSc vector - inline void operator>>(const Vec& petscVec, DOFVector<double>& vec) - { - // Traverse all used DOFs in the dof vector. - DOFVector<double>::Iterator dofIt(&vec, USED_DOFS); - PetscInt index = 0; - for (dofIt.reset(); !dofIt.end(); ++dofIt, ++index) { - double value = 0.0; - VecGetValues(petscVec, 1, &index, &value); - *dofIt = value; - } - } - - - /// fill PETSc vector from DOFVector - inline void operator<<(Vec& petscVec, const SystemVector& vec) - { -#ifdef VecType // PETSc uses MACROS instead of typedefs in Versions 3.3x - const VecType vecType; -#else - VecType vecType; -#endif - VecGetType(petscVec, &vecType); - - if (strcmp(vecType, VECNEST) == 0) { - for (size_t i = 0; i < static_cast<size_t>(vec.getSize()); i++) { - Vec v; - VecNestGetSubVec(petscVec, i, &v); - v << *(vec.getDOFVector(i)); - } - } else { - PetscInt index = 0; - for (size_t i = 0; i < static_cast<size_t>(vec.getSize()); i++) { - DOFConstIterator<double> dofIt(vec.getDOFVector(i), USED_DOFS); - for (dofIt.reset(); !dofIt.end(); ++dofIt, ++index) { - double value = *dofIt; - VecSetValue(petscVec, index, value, ADD_VALUES); - } - } - } - } - - - /// fill SystemVector from PETSc vector - inline void operator>>(const Vec& petscVec, SystemVector& vec) - { -#ifdef VecType // PETSc uses MACROS instead of typedefs in Versions 3.3x - const VecType vecType; -#else - VecType vecType; -#endif - VecGetType(petscVec, &vecType); - - if (strcmp(vecType, VECNEST) == 0) { - for (size_t i = 0; i < static_cast<size_t>(vec.getSize()); i++) { - Vec v; - VecNestGetSubVec(petscVec, i, &v); - v >> *(vec.getDOFVector(i)); - } - } else { - PetscInt n = 0; - for (size_t i = 0; i < static_cast<size_t>(vec.getSize()); i++) - n += vec.getDOFVector(i)->getUsedSize(); - - PetscInt N = 0; - VecGetSize(petscVec, &N); - assert(n == N); - - PetscInt index = 0; - for (size_t i = 0; i < static_cast<size_t>(vec.getSize()); i++) { - DOFVector<double>::Iterator dofIt(vec.getDOFVector(i), USED_DOFS); - for (dofIt.reset(); !dofIt.end(); ++dofIt, ++index) { - double value = 0.0; - VecGetValues(petscVec, 1, &index, &value); - *dofIt = value; - } - } - } - } - - - /// create and fill \ref PetscVector - inline void operator<<(PetscVector& petscVec, const SystemVector& rhs) - { - size_t nComponents = rhs.getSize(); - if (petscVec.assembled) - petscVec.destroy(); - - // only create nested vector if requested, i.e. flag createNestedVector is set to true - if (petscVec.isNested) { - petscVec.nestVec.resize(nComponents); - - for (size_t i = 0; i < nComponents; i++) { - VecCreateSeq(PETSC_COMM_SELF,rhs.getDOFVector(i)->getUsedSize(), &(petscVec.nestVec[i])); - - petscVec.nestVec[i] << *(rhs.getDOFVector(i)); - - VecAssemblyBegin(petscVec.nestVec[i]); - VecAssemblyEnd(petscVec.nestVec[i]); - } - - // create nested vector from vector of block vectors - VecCreateNest(PETSC_COMM_SELF, nComponents, PETSC_NULL, &(petscVec.nestVec[0]), &(petscVec.vector)); - } else { - PetscInt n = 0; - for (size_t i = 0; i < nComponents; i++) - n += rhs.getDOFVector(i)->getUsedSize(); - - VecCreateSeq(PETSC_COMM_SELF, n, &(petscVec.vector)); - petscVec.vector << rhs; - } - petscVec.assembled = true; - } - -#endif - } #endif // AMDIS_MATRIXSTREAMS_H diff --git a/AMDiS/src/solver/PetscSolver.cc b/AMDiS/src/solver/PetscSolver.cc index 256d885ebbcbe5be527696a97fee2dc9928ac5de..710cb81754175a008d4377fb5383642039c148e8 100644 --- a/AMDiS/src/solver/PetscSolver.cc +++ b/AMDiS/src/solver/PetscSolver.cc @@ -22,141 +22,14 @@ #ifdef HAVE_SEQ_PETSC #include "solver/PetscSolver.h" - -using namespace std; +#include "solver/PetscTypes.h" namespace AMDiS { - PetscRunner::PetscRunner(LinearSolver* oem_) - : oem(*oem_), - kspPrefix(""), - zeroStartVector(false), - initialized(false) - { - PetscParameters params; - bool matSolverPackage = false; - - // set the parameter prefix - Parameters::get(oem.getName() + "->petsc prefix", kspPrefix); // important when more than one solver to configure - - // set the solver - std::string solverName = "petsc"; - Parameters::get(oem.getName(), solverName); - if (solverName == "petsc") - Parameters::get(oem.getName() + "->ksp_type", solverName); - - std::string kspSolver = params.solverMap[solverName]; - - if (params.matSolverPackage[kspSolver]) { - // direct solvers - PetscOptionsInsertString(("-" + kspPrefix + "ksp_type preonly").c_str()); - PetscOptionsInsertString(("-" + kspPrefix + "pc_type lu").c_str()); - PetscOptionsInsertString(("-" + kspPrefix + "pc_factor_mat_solver_package " + (kspSolver != "direct" ? kspSolver : "umfpack")).c_str()); - oem.setMaxIterations(1); - zeroStartVector = true; - matSolverPackage = true; - } else if (!params.emptyParam[kspSolver]) { - // other solvers - PetscOptionsInsertString(("-" + kspPrefix + "ksp_type " + kspSolver).c_str()); - } - - // set the preconditioner - string precon = ""; - Parameters::get(oem.getName() + "->pc_type", precon); - if (!precon.size()) - Parameters::get(oem.getName() + "->left precon", precon); - if (!precon.size()) - Parameters::get(oem.getName() + "->right precon", precon); - if (!matSolverPackage && !params.emptyParam[precon]) { - precon = (params.preconMap.find(precon) != params.preconMap.end() ? params.preconMap[precon] : precon); - PetscOptionsInsertString(("-" + kspPrefix + "pc_type " + precon).c_str()); - } - - if (oem.getInfo() >= 20) - PetscOptionsInsertString(("-" + kspPrefix + "ksp_monitor_true_residual").c_str()); - else if (oem.getInfo() >= 10) - PetscOptionsInsertString(("-" + kspPrefix + "ksp_monitor").c_str()); - - // command line string - string kspString = ""; - Parameters::get(oem.getName() + "->ksp", kspString); - if (kspString != "") - PetscOptionsInsertString(kspString.c_str()); - } - - - void PetscRunner::init(const BlockMatrix& A, const Mat& fullMatrix) - { - if (initialized) - exit(); - - createSubSolver(ksp, fullMatrix, kspPrefix); - - // set tolerance options from LinearSolver-parameters - KSPSetTolerances(ksp, oem.getRelative(), oem.getTolerance(), PETSC_DEFAULT, oem.getMaxIterations()); - - // Do not delete the solution vector, use it for the initial guess. - if (!zeroStartVector) - KSPSetInitialGuessNonzero(ksp, PETSC_TRUE); - - KSPGetPC(ksp, &pc); - PCSetFromOptions(pc); - - initialized = true; - } - + // explicit template instantiation + template class PetscRunner<PetscMatrix, PetscVector>; + template class PetscRunner<PetscMatrixNested, PetscVectorNested>; - int PetscRunner::solve(const Mat& A, Vec& x, const Vec& b) - { - if (zeroStartVector) - VecSet(x, 0.0); - - PetscErrorCode solverError = KSPSolve(ksp, b, x); - - PetscInt nIter = 0; - KSPGetIterationNumber(ksp, &nIter); - PetscReal residual_norm = -1.0; - KSPGetResidualNorm(ksp, &residual_norm); - - if (residual_norm <= 0.0) { - Vec r; - VecDuplicate(b, &r); - KSPBuildResidual(ksp, PETSC_NULL, PETSC_NULL, &r); - VecNorm(r, NORM_2, &residual_norm); - } - - oem.setErrorCode(solverError); - oem.setIterations(nIter); - oem.setResidual(residual_norm); - - return solverError; - } - - - void PetscRunner::createSubSolver(KSP &ksp_, Mat m, string kspPrefix_) - { - KSPCreate(PETSC_COMM_SELF, &ksp_); - KSPSetOperators(ksp_, m, m, SAME_NONZERO_PATTERN); - KSPSetOptionsPrefix(ksp_, kspPrefix_.c_str()); - KSPSetFromOptions(ksp_); - } - - - void PetscRunner::setSolver(KSP ksp_, std::string kspPrefix_, - KSPType kspType, PCType pcType, - PetscReal rtol, PetscReal atol, PetscInt maxIt) - { - KSPSetType(ksp_, kspType); - KSPSetTolerances(ksp_, rtol, atol, PETSC_DEFAULT, maxIt); - if (kspPrefix_ != "") - KSPSetOptionsPrefix(ksp_, kspPrefix_.c_str()); - KSPSetFromOptions(ksp_); - - PC pc_; - KSPGetPC(ksp_, &pc_); - PCSetType(pc_, pcType); - PCSetFromOptions(pc_); - } } #endif // HAVE_SEQ_PETSC diff --git a/AMDiS/src/solver/PetscSolver.h b/AMDiS/src/solver/PetscSolver.h index 1ee3e5e0cfda218ba42f92834dc83ca82de5638e..c750c484ef6ac3864d58d799abc6987e4886a6b6 100644 --- a/AMDiS/src/solver/PetscSolver.h +++ b/AMDiS/src/solver/PetscSolver.h @@ -26,9 +26,9 @@ #ifdef HAVE_SEQ_PETSC -#include "solver/LinearSolver.h" -#include "solver/MatrixStreams.h" +#include "solver/MTL4Solver.h" #include "solver/PetscTypes.h" +#include "solver/MatrixStreams.h" #include "Timer.h" #include <vector> #include <iostream> @@ -42,42 +42,90 @@ #include <petscao.h> namespace AMDiS { + + /** + * \ingroup Solver + * + * \brief Common base class for wrappers to use Petsc preconditioners in AMDiS. + */ + template< class MatrixType, class VectorType > + struct Petsc_BasePreconditioner : public OEMPreconditioner + { + Petsc_BasePreconditioner(std::string prefix, std::string name) : prefix(prefix), name(name) {} + virtual ~Petsc_BasePreconditioner() {} + + virtual void init(PC pc, const SolverMatrix<Matrix<DOFMatrix*> >& A, const MatrixType& fullMatrix) + { + PetscOptionsInsertString(("-" + prefix + "pc_type " + name).c_str()); + PCSetFromOptions(pc); + } + + virtual void exit() {} + + protected: + std::string prefix; + std::string name; + }; + + + typedef Petsc_BasePreconditioner<PetscMatrix, PetscVector> PetscPreconditioner; + typedef Petsc_BasePreconditioner<PetscMatrixNested, PetscVectorNested> PetscPreconditionerNested; + + template<typename MatrixType, typename VectorType> class PetscRunner : public OEMRunner { public: /// Constructor of standard PETSc runner. Reads ksp and pc parameters from initfile. - PetscRunner(LinearSolver* oem_); - - typedef SolverMatrix<Matrix<DOFMatrix*> > BlockMatrix; + PetscRunner(LinearSolver* oem); + + /// Destructor, deletes preconditioner object \ref preconditioner + ~PetscRunner() + { + if (preconditioner) { + delete preconditioner; + preconditioner = NULL; + } + } - /// initialize the solver \ref ksp and preconditioner \ref pc - void init(const BlockMatrix& A, const Mat& fullMatrix); + /// Initialize the solver \ref ksp and preconditioner \ref pc + void init(const SolverMatrix<Matrix<DOFMatrix*> >& A, const MatrixType& fullMatrix); - /// solve the linear equation \f$ A\cdot x = b \f$ by applying the PETSc solver \ref ksp - int solve(const Mat& A, Vec& x, const Vec& b); + /// Solve the linear equation \f$ A\cdot x = b \f$ by applying the PETSc solver \ref ksp + int solve(const MatrixType& A, VectorType& x, const VectorType& b); - /// destroy solver \ref ksp and preconditioner \ref pc + /// Destroy solver \ref ksp and preconditioner \ref pc virtual void exit() { + preconditioner->exit(); KSPDestroy(&ksp); } - /// get the PETSc solver \ref ksp + /// Get the PETSc solver \ref ksp KSP getSolver() { return ksp; } - /// get the PETSc preconditioner \ref pc + /// Get the PETSc preconditioner \ref pc PC getPc() { return pc; } - ~PetscRunner() { } + /// Returns preconditioner object \ref preconditioner + OEMPreconditioner* getLeftPrecon() + { + return preconditioner; + } + + /// Returns preconditioner object \ref preconditioner + OEMPreconditioner* getRightPrecon() + { + return preconditioner; + } + - protected: static void createSubSolver(KSP &ksp_, Mat m, std::string kspPrefix_); static void setSolver(KSP ksp_, std::string kspPrefix_, @@ -85,10 +133,15 @@ namespace AMDiS { PetscReal rtol = PETSC_DEFAULT, PetscReal atol = PETSC_DEFAULT, PetscInt maxIt = PETSC_DEFAULT); - + + + protected: + /// Creates a preconditioner object \ref preconditioner + void setPrecon(); + + protected: LinearSolver& oem; - //private: /// PETSc solver object KSP ksp; @@ -98,8 +151,12 @@ namespace AMDiS { /// KSP database prefix std::string kspPrefix; - bool zeroStartVector; - bool initialized; + bool zeroStartVector; ///< initialize startsolution for iterative solver with 0 + bool initialized; ///< true when \ref init() was called + bool matSolverPackage; ///< true when using a direct solver + + /// Preconditioner object, that set parameters to \ref pc + Petsc_BasePreconditioner<MatrixType, VectorType>* preconditioner; }; @@ -113,100 +170,13 @@ namespace AMDiS { * This is a suite of data structures and routines for the * scalable (parallel) solution of scientific applications. */ - template< typename Runner = PetscRunner > - class PetscSolver : public LinearSolver - { - public: - /// Creator class used in the LinearSolverMap. - class Creator : public LinearSolverCreator - { - public: - virtual ~Creator() {} - - /// Returns a new PetscSolver object. - LinearSolver* create() - { - return new PetscSolver<Runner>(this->name); - } - }; - - PetscSolver(std::string n) - : LinearSolver(n), - runner(this) - {} - - ~PetscSolver() {} - - virtual OEMRunner* getRunner() - { - return &runner; - } - - void setNestedVectors(bool nested = true) - { - vecSol.isNested = nested; - vecRhs.isNested = nested; - } - - void setNestedMatrix(bool nested = true) - { - petscMat.isNested=nested; - } - - void setNested(bool n) - { - setNestedVectors(n); - setNestedMatrix(n); - } - - protected: - Runner runner; - - int solveLinearSystem(const SolverMatrix<Matrix<DOFMatrix*> >& A, - SystemVector& x, - SystemVector& b, - bool createMatrixData, - bool storeMatrixData) - { FUNCNAME("PetscSolver::solveLinearSystem()"); - - Timer t; - // transfer matrix and rhs-vector to PETSc data-structures - if (createMatrixData) { - petscMat << A; - runner.init(A, petscMat.matrix); - } - - vecSol << x; - vecRhs << b; - INFO(info, 8)("fill PETSc matrix needed %.5f seconds\n", t.elapsed()); - - // solve the linear system using PETSc solvers - t.reset(); - error = runner.solve(petscMat.matrix, vecSol.vector, vecRhs.vector); - - // transfer solution from PETSc vector to SystemVector - vecSol.vector >> x; - - vecSol.destroy(); - vecRhs.destroy(); - - if (!storeMatrixData) { - petscMat.destroy(); - runner.exit(); - } - return error; - } - - private: - /// PETSc System-Matrix - PetscMatrix petscMat; - - /// Solution and RHS vectors. - PetscVector vecSol, vecRhs; - }; + typedef MTL4Solver< PetscMatrix, PetscVector, PetscRunner<PetscMatrix, PetscVector> > PetscSolver; + typedef MTL4Solver< PetscMatrixNested, PetscVectorNested, PetscRunner<PetscMatrixNested, PetscVectorNested> > PetscSolverNested; } // end namespace AMDiS #endif // HAVE_SEQ_PETSC +#include "solver/PetscSolver.hh" + #endif // AMDIS_PETSC_SOLVER_SEQ_H diff --git a/AMDiS/src/solver/PetscSolver.hh b/AMDiS/src/solver/PetscSolver.hh new file mode 100644 index 0000000000000000000000000000000000000000..096178c7f3b4fb3d3732b19b8936fab9d665095c --- /dev/null +++ b/AMDiS/src/solver/PetscSolver.hh @@ -0,0 +1,205 @@ +/****************************************************************************** + * + * AMDiS - Adaptive multidimensional simulations + * + * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved. + * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis + * + * Authors: + * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * + * This file is part of AMDiS + * + * See also license.opensource.txt in the distribution. + * + ******************************************************************************/ + + +#ifdef HAVE_SEQ_PETSC + +namespace AMDiS { + + template<typename M, typename V> + PetscRunner<M,V>::PetscRunner(LinearSolver* oem_) + : oem(*oem_), + kspPrefix(""), + zeroStartVector(false), + initialized(false), + preconditioner(NULL) + { + PetscParameters params; + matSolverPackage = false; + + // set the parameter prefix + Parameters::get(oem.getName() + "->petsc prefix", kspPrefix); // important when more than one solver to configure + + // set the solver + std::string solverName = "petsc"; + Parameters::get(oem.getName(), solverName); + if (solverName == "petsc") + Parameters::get(oem.getName() + "->ksp_type", solverName); + + std::string kspSolver = params.solverMap[solverName]; + + if (params.matSolverPackage[kspSolver]) { + // direct solvers + PetscOptionsInsertString(("-" + kspPrefix + "ksp_type preonly").c_str()); + PetscOptionsInsertString(("-" + kspPrefix + "pc_type lu").c_str()); + PetscOptionsInsertString(("-" + kspPrefix + "pc_factor_mat_solver_package " + (kspSolver != "direct" ? kspSolver : "umfpack")).c_str()); + oem.setMaxIterations(1); + zeroStartVector = true; + matSolverPackage = true; + } else if (!params.emptyParam[kspSolver]) { + // other solvers + PetscOptionsInsertString(("-" + kspPrefix + "ksp_type " + kspSolver).c_str()); + } + + // set the preconditioner + setPrecon(); + + if (oem.getInfo() >= 20) + PetscOptionsInsertString(("-" + kspPrefix + "ksp_monitor_true_residual").c_str()); + else if (oem.getInfo() >= 10) + PetscOptionsInsertString(("-" + kspPrefix + "ksp_monitor").c_str()); + + // command line string + std::string kspString = ""; + Parameters::get(oem.getName() + "->ksp", kspString); + if (kspString != "") + PetscOptionsInsertString(kspString.c_str()); + } + + + template<typename MatrixType, typename VectorType> + void PetscRunner<MatrixType, VectorType>::init(const SolverMatrix<Matrix<DOFMatrix*> >& A, const MatrixType& fullMatrix) + { + if (initialized) + exit(); + + createSubSolver(ksp, fullMatrix.matrix, kspPrefix); + + // set tolerance options from LinearSolver-parameters + KSPSetTolerances(ksp, oem.getRelative(), oem.getTolerance(), PETSC_DEFAULT, oem.getMaxIterations()); + + // Do not delete the solution vector, use it for the initial guess. + if (!zeroStartVector) + KSPSetInitialGuessNonzero(ksp, PETSC_TRUE); + + KSPGetPC(ksp, &pc); + + preconditioner->init(pc, A, fullMatrix); + initialized = true; + } + + + template<typename MatrixType, typename VectorType> + int PetscRunner<MatrixType, VectorType>::solve(const MatrixType& A, VectorType& x, const VectorType& b) + { + if (zeroStartVector) + VecSet(x.vector, 0.0); + + PetscErrorCode solverError = KSPSolve(ksp, b.vector, x.vector); + + PetscInt nIter = 0; + KSPGetIterationNumber(ksp, &nIter); + PetscReal residual_norm = -1.0; + KSPGetResidualNorm(ksp, &residual_norm); + + if (residual_norm <= 0.0) { + Vec r; + VecDuplicate(b.vector, &r); + KSPBuildResidual(ksp, PETSC_NULL, PETSC_NULL, &r); + VecNorm(r, NORM_2, &residual_norm); + } + + oem.setErrorCode(solverError); + oem.setIterations(nIter); + oem.setResidual(residual_norm); + + return solverError; + } + + + template<typename M, typename V> + void PetscRunner<M,V>::createSubSolver(KSP &ksp_, Mat m, std::string kspPrefix_) + { + KSPCreate(PETSC_COMM_SELF, &ksp_); +#if (PETSC_VERSION_MINOR >= 5) + KSPSetOperators(ksp_, m, m); +#else + KSPSetOperators(ksp_, m, m, SAME_NONZERO_PATTERN); +#endif + KSPSetOptionsPrefix(ksp_, kspPrefix_.c_str()); + KSPSetFromOptions(ksp_); + } + + + template<typename M, typename V> + void PetscRunner<M,V>::setSolver(KSP ksp_, std::string kspPrefix_, + KSPType kspType, PCType pcType, + PetscReal rtol, PetscReal atol, PetscInt maxIt) + { + KSPSetType(ksp_, kspType); + KSPSetTolerances(ksp_, rtol, atol, PETSC_DEFAULT, maxIt); + if (kspPrefix_ != "") + KSPSetOptionsPrefix(ksp_, kspPrefix_.c_str()); + KSPSetFromOptions(ksp_); + + PC pc_; + KSPGetPC(ksp_, &pc_); + PCSetType(pc_, pcType); + PCSetFromOptions(pc_); + } + + + template<typename MatrixType, typename VectorType> + void PetscRunner<MatrixType, VectorType>::setPrecon() + { + std::string precon = ""; + std::string initFileStr = oem.getName() + "->pc_type"; + Parameters::get(initFileStr, precon); + if (!precon.size() || precon == "no" || precon == "0") { + initFileStr = oem.getName() + "->left precon"; + Parameters::get(initFileStr, precon); + } + if (!precon.size() || precon == "no" || precon == "0") { + initFileStr = oem.getName() + "->right precon"; + Parameters::get(initFileStr, precon); + } + // no preconditioner should be created + if (!precon.size() || precon == "no" || precon == "0") + return; + + PetscParameters params; + if (preconditioner) { + delete preconditioner; + preconditioner = NULL; + } + + // Creator for the left preconditioner + CreatorInterfaceName< Petsc_BasePreconditioner<MatrixType, VectorType> >* creator(NULL); + + try { + creator = dynamic_cast<CreatorInterfaceName< Petsc_BasePreconditioner<MatrixType, VectorType> >*>( + CreatorMap<Petsc_BasePreconditioner<MatrixType, VectorType> >::getCreator(precon, initFileStr) ); + } catch (...) { + creator = NULL; + } + + if (creator) { + creator->setName(initFileStr); + preconditioner = creator->create(); + } else if (!matSolverPackage && !params.emptyParam[precon]) { + precon = (params.preconMap.find(precon) != params.preconMap.end() ? params.preconMap[precon] : precon); + preconditioner = new Petsc_BasePreconditioner<MatrixType, VectorType>(kspPrefix, precon); + } else { + ERROR_EXIT((std::string("There is no creator for the given preconditioner '") + precon + "'").c_str()); + } + } +} + +#endif // HAVE_SEQ_PETSC diff --git a/AMDiS/src/solver/PetscTypes.h b/AMDiS/src/solver/PetscTypes.h index 8802c4195d4a55fa592513cb4fe1954698f43f1d..504017af6c4b77ba3934a80ee238659be23452e8 100644 --- a/AMDiS/src/solver/PetscTypes.h +++ b/AMDiS/src/solver/PetscTypes.h @@ -23,11 +23,14 @@ #define AMDIS_PETSCTYPES_H #include <vector> +#include <map> +#include <string> + +#include "MatrixStreams.h" + #include <petsc.h> #include <petscmat.h> #include <petscvec.h> -#include <map> -#include <string> namespace AMDiS { @@ -38,6 +41,8 @@ namespace AMDiS { : matrix(PETSC_NULL), isNested(false), assembled(false) {} + + ~PetscMatrix() { destroy(); } std::vector<Mat> nestMat; Mat matrix; @@ -47,6 +52,14 @@ namespace AMDiS { bool assembled; }; + struct PetscMatrixNested : PetscMatrix + { + PetscMatrixNested() : PetscMatrix() + { + isNested = true; + } + }; + /// pair of nested vectors and blockvector struct PetscVector @@ -55,6 +68,8 @@ namespace AMDiS { : vector(PETSC_NULL), isNested(false), assembled(false) {} + + ~PetscVector() { destroy(); } std::vector<Vec> nestVec; Vec vector; @@ -64,6 +79,13 @@ namespace AMDiS { bool assembled; }; + struct PetscVectorNested : PetscVector + { + PetscVectorNested() : PetscVector() + { + isNested = true; + } + }; /// structure for parameter mapping struct PetscParameters @@ -76,6 +98,53 @@ namespace AMDiS { PetscParameters(); }; -} + + // matrix-streams for Petsc Types + // ___________________________________________________________________________ + + /// fill Petsc Mat datastructure directly + inline void operator<<(Mat& mat, const DOFMatrix& rhs); + + /// fill PetscMatrix + template< typename Mapper > + inline void operator<<(PetscMatrix& mat, MatMap<const SolverMatrix<Matrix<DOFMatrix* > >, Mapper >& rhs); + + /// fill nested PetscMatrix + template< typename Mapper > + inline void operator<<(PetscMatrixNested& mat, MatMap<const SolverMatrix<Matrix<DOFMatrix* > >, Mapper >& mapper); + + + /// fill Petsc Vec datastructure directly from DOFVector + inline void operator<<(Vec& petscVec, const DOFVector<double>& vec); + + /// fill Petsc Vec datastructure directly from SystemVector + inline void operator<<(Vec& petscVec, const SystemVector& vec); + + inline void operator<<(PetscVector& petscVec, const SystemVector& rhs); + + template< typename Mapper > + inline void operator<<(PetscVector& petscVec, VecMap<const SystemVector, Mapper>& rhs); + + template< typename Mapper > + inline void operator<<(PetscVectorNested& petscVec, VecMap<const SystemVector, Mapper>& rhs); + + + /// fill AMDiS DOFVector from Petsc Vec datastructur + inline void operator>>(const Vec& petscVec, DOFVector<double>& vec); + + /// fill AMDiS SystemVector from Petsc Vec datastructur + inline void operator>>(const Vec& petscVec, SystemVector& vec); + + /// fill AMDiS SystemVector from PetscVector + template< typename Mapper > + void operator>>(const PetscVector& dest, VecMap<SystemVector, Mapper>& rhs); + + /// fill AMDiS SystemVector from nested PetscVector + template< typename Mapper > + void operator>>(const PetscVectorNested& dest, VecMap<SystemVector, Mapper>& rhs); + +} // end namespace AMDiS + +#include "solver/PetscTypes.hh" #endif // AMDIS_PETSCTYPES_H diff --git a/AMDiS/src/solver/PetscTypes.hh b/AMDiS/src/solver/PetscTypes.hh new file mode 100644 index 0000000000000000000000000000000000000000..774650909683305d6c09f1056f274489825fca18 --- /dev/null +++ b/AMDiS/src/solver/PetscTypes.hh @@ -0,0 +1,295 @@ +#ifdef HAVE_SEQ_PETSC + +namespace AMDiS { + + inline void operator<<(Mat& mat, const DOFMatrix& rhs) + { + bool initMatrix = false; + if (mat == PETSC_NULL) { + std::vector<PetscInt> nnz(rhs.getSize()); + for (size_t k = 0; k < static_cast<size_t>(rhs.getSize()); k++) + nnz[k] = rhs.getBaseMatrix().nnz_local(k); + + MatCreateSeqAIJ(PETSC_COMM_SELF, num_rows(rhs.getBaseMatrix()), num_cols(rhs.getBaseMatrix()), 0, &(nnz[0]), &mat); + initMatrix = true; + } + + std::vector<PetscInt> indices; + for (size_t i = 0; i < rhs.getBaseMatrix().ref_minor().size(); i++) + indices.push_back(rhs.getBaseMatrix().ref_minor()[i]); + + for (PetscInt i = 0; i < static_cast<PetscInt>(num_rows(rhs.getBaseMatrix())); i++) { + if (rhs.getBaseMatrix().nnz_local(i) > 0) + MatSetValues(mat, 1, &i, rhs.getBaseMatrix().nnz_local(i), + &(indices[rhs.getBaseMatrix().ref_major()[i]]), + &(rhs.getBaseMatrix().value_from_offset(rhs.getBaseMatrix().ref_major()[i])), ADD_VALUES); + } + + if (initMatrix) { + MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY); + MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY); + } + } + + + template< typename Mapper > + inline void operator<<(PetscMatrix& mat, MatMap<const SolverMatrix<Matrix<DOFMatrix* > >, Mapper >& rhs) + { + if (mat.assembled) + mat.destroy(); + + const Matrix< DOFMatrix* >& A = *(rhs.mat.getOriginalMat()); + + bool initMatrix = false; + unsigned nRows(0); + unsigned nEntries(0); + std::vector< int > nRowsBlock(A.getNumRows()); + for(int i(0); i < A.getNumRows(); ++i) { + int j(0); + for( ; j<A.getNumCols() && A[i][j] == NULL; ++j) ; + if( j == A.getNumCols() ) { + std::stringstream ss; ss << "ERROR: solver matrix has empty row " << i << "\n"; + throw std::runtime_error(ss.str()); + } + nRowsBlock[i]=num_rows(A[i][j]->getBaseMatrix()); + nRows+=nRowsBlock[i]; + } + std::vector<PetscInt> nnz(nRows); + + //initialize the nnz (could be avoided, but gets complicated) + for (int i(0); i < nRows; ++i) + nnz[i] = 0; + + //build a list of pairs (col, value) for each row + std::vector< std::list< std::pair<int, double > > > rowData(nRows); + + PetscInt maxNnz(0); + Mapper &mapper = rhs.mapper; + for (int i(0); i < A.getNumRows(); ++i) { + mapper.setRow(i); + //compute the number of nonzeros per global row + for (int j(0); j < A.getNumCols(); ++j) { + if (A[i][j] != NULL) { + mapper.setCol(j); + const DOFMatrix::base_matrix_type& mtlMat(A[i][j]->getBaseMatrix()); + for (unsigned k(0); k < nRowsBlock[i]; ++k) { + unsigned curRow(mapper.row(k)); + nnz[curRow] += mtlMat.nnz_local(k); + maxNnz = std::max(maxNnz, nnz[curRow]); + unsigned curPos(mtlMat.ref_major()[k]); + for(unsigned l(0); l < mtlMat.nnz_local(k); ++l, ++curPos) { + rowData[curRow].push_back(std::make_pair(mapper.col(mtlMat.ref_minor()[curPos]), mtlMat.data[curPos])); + } + } + } + } + + } + if (mat.matrix == PETSC_NULL) { + MatCreateSeqAIJ(PETSC_COMM_SELF, nRows, nRows, 0, &(nnz[0]), &mat.matrix); + initMatrix = true; + } + //reduce mallocs.. + std::vector< PetscInt > colIndices(maxNnz); + std::vector< PetscScalar > values(maxNnz); + std::list< std::pair< int, double > >::iterator it; + unsigned j; + for (PetscInt i(0); i < nRows; ++i) { + j=0; it = rowData[i].begin(); + for (; it != rowData[i].end(); ++it, ++j) { + colIndices[j] = it->first; + values[j] = it->second; + } + MatSetValues(mat.matrix, 1, &i, nnz[i], &colIndices[0], &values[0], INSERT_VALUES); + } + if (initMatrix) { + MatAssemblyBegin(mat.matrix, MAT_FINAL_ASSEMBLY); + MatAssemblyEnd(mat.matrix, MAT_FINAL_ASSEMBLY); + } + + mat.assembled = true; + } + + + template< typename Mapper > + inline void operator<<(PetscMatrixNested& mat, MatMap<const SolverMatrix<Matrix<DOFMatrix* > >, Mapper >& mapper) + { + if (mat.assembled) + mat.destroy(); + + const Matrix< DOFMatrix* >& A = *(mapper.mat.getOriginalMat()); + + std::vector<PetscInt> nnz; + mat.nestMat.resize(A.getNumRows() * A.getNumCols()); + + for (unsigned int i = 0; i < A.getNumRows(); i++) { + for (unsigned int j = 0; j < A.getNumCols(); j++) { + size_t idx = i * A.getNumCols() + j; + + if (!(A[i][j]) + || num_rows(A[i][j]->getBaseMatrix()) == 0 + || num_cols(A[i][j]->getBaseMatrix()) == 0 + || A[i][j]->getBaseMatrix().nnz() == 0) { + mat.nestMat[idx] = PETSC_NULL; + continue; + } + + mat.nestMat[idx] << *(A[i][j]); + } + } + + // create nested matrix from a vector of block matrices + MatCreateNest(PETSC_COMM_SELF, A.getNumRows(), PETSC_NULL, A.getNumCols(), PETSC_NULL, &(mat.nestMat[0]), &mat.matrix); + mat.assembled = true; + } + + + inline void operator<<(Vec& petscVec, const DOFVector<double>& vec) + { + // Traverse all used DOFs in the dof vector. + DOFConstIterator<double> dofIt(&vec, USED_DOFS); + PetscInt index = 0; + for (dofIt.reset(); !dofIt.end(); ++dofIt, ++index) { + double value = *dofIt; + VecSetValue(petscVec, index, value, ADD_VALUES); + } + } + + + inline void operator>>(const Vec& petscVec, DOFVector<double>& vec) + { + // Traverse all used DOFs in the dof vector. + DOFVector<double>::Iterator dofIt(&vec, USED_DOFS); + PetscInt index = 0; + for (dofIt.reset(); !dofIt.end(); ++dofIt, ++index) { + double value = 0.0; + VecGetValues(petscVec, 1, &index, &value); + *dofIt = value; + } + } + + + inline void operator<<(Vec& petscVec, const SystemVector& vec) + { +#ifdef VecType // PETSc uses MACROS instead of typedefs in Versions 3.3x + const VecType vecType; +#else + VecType vecType; +#endif + VecGetType(petscVec, &vecType); + + if (strcmp(vecType, VECNEST) == 0) { + for (size_t i = 0; i < static_cast<size_t>(vec.getSize()); i++) { + Vec v; + VecNestGetSubVec(petscVec, i, &v); + v << *(vec.getDOFVector(i)); + } + } else { + PetscInt index = 0; + for (size_t i = 0; i < static_cast<size_t>(vec.getSize()); i++) { + DOFConstIterator<double> dofIt(vec.getDOFVector(i), USED_DOFS); + for (dofIt.reset(); !dofIt.end(); ++dofIt, ++index) { + double value = *dofIt; + VecSetValue(petscVec, index, value, ADD_VALUES); + } + } + } + } + + + inline void operator>>(const Vec& petscVec, SystemVector& vec) + { +#ifdef VecType // PETSc uses MACROS instead of typedefs in Versions 3.3x + const VecType vecType; +#else + VecType vecType; +#endif + VecGetType(petscVec, &vecType); + + if (strcmp(vecType, VECNEST) == 0) { + for (size_t i = 0; i < static_cast<size_t>(vec.getSize()); i++) { + Vec v; + VecNestGetSubVec(petscVec, i, &v); + v >> *(vec.getDOFVector(i)); + } + } else { + PetscInt n = 0; + for (size_t i = 0; i < static_cast<size_t>(vec.getSize()); i++) + n += vec.getDOFVector(i)->getUsedSize(); + + PetscInt N = 0; + VecGetSize(petscVec, &N); + assert(n == N); + + PetscInt index = 0; + for (size_t i = 0; i < static_cast<size_t>(vec.getSize()); i++) { + DOFVector<double>::Iterator dofIt(vec.getDOFVector(i), USED_DOFS); + for (dofIt.reset(); !dofIt.end(); ++dofIt, ++index) { + double value = 0.0; + VecGetValues(petscVec, 1, &index, &value); + *dofIt = value; + } + } + } + } + + + template< typename Mapper > + void operator>>(const PetscVector& dest, VecMap<SystemVector, Mapper>& rhs) + { + dest.vector >> rhs.vec; + } + + + template< typename Mapper > + void operator>>(const PetscVectorNested& dest, VecMap<SystemVector, Mapper>& rhs) + { + dest.vector >> rhs.vec; + } + + + template< typename Mapper > + inline void operator<<(PetscVector& petscVec, VecMap<const SystemVector, Mapper>& rhs) + { + size_t nComponents = rhs.vec.getSize(); + if (petscVec.assembled) + petscVec.destroy(); + + PetscInt n = 0; + for (size_t i = 0; i < nComponents; i++) + n += rhs.vec.getDOFVector(i)->getUsedSize(); + + VecCreateSeq(PETSC_COMM_SELF, n, &(petscVec.vector)); + petscVec.vector << rhs.vec; + + petscVec.assembled = true; + } + + + template< typename Mapper > + inline void operator<<(PetscVectorNested& petscVec, VecMap<const SystemVector, Mapper>& rhs) + { + size_t nComponents = rhs.mapper.getNumComponents(); + if (petscVec.assembled) + petscVec.destroy(); + + petscVec.nestVec.resize(nComponents); + + for (size_t i = 0; i < nComponents; i++) { + VecCreateSeq(PETSC_COMM_SELF,rhs.mapper.getNumRows(i), &(petscVec.nestVec[i])); + + petscVec.nestVec[i] << *(rhs.vec.getDOFVector(i)); + + VecAssemblyBegin(petscVec.nestVec[i]); + VecAssemblyEnd(petscVec.nestVec[i]); + } + + // create nested vector from vector of block vectors + VecCreateNest(PETSC_COMM_SELF, nComponents, PETSC_NULL, &(petscVec.nestVec[0]), &(petscVec.vector)); + + petscVec.assembled = true; + } + +} // end namespace AMDiS + +#endif diff --git a/AMDiS/src/solver/TriangularPreconditioner.h b/AMDiS/src/solver/TriangularPreconditioner.h new file mode 100644 index 0000000000000000000000000000000000000000..b79dae83413211bc96c39f4e9d23008045140e1d --- /dev/null +++ b/AMDiS/src/solver/TriangularPreconditioner.h @@ -0,0 +1,104 @@ +/****************************************************************************** + * + * AMDiS - Adaptive multidimensional simulations + * + * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved. + * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis + * + * Authors: + * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * + * This file is part of AMDiS + * + * See also license.opensource.txt in the distribution. + * + ******************************************************************************/ + + +/** \file TriangularPreconditioner.h */ + +#ifndef AMDIS_TRIANGULAR_PRECONDITIONER_H +#define AMDIS_TRIANGULAR_PRECONDITIONER_H + +#include "solver/CombinedPreconditioner.h" + +namespace AMDiS { + + /// preconditioner structure that combines various block-preconditioners + template<typename MatrixType> + struct TriangularPreconditioner : CombinedPreconditioner<MatrixType> + { + typedef CombinedPreconditioner<MatrixType> super; + typedef ITL_BasePreconditioner<MatrixType, MTLTypes::MTLVector> precon_base; + typedef TriangularPreconditioner<MatrixType> self; + + class Creator : public CreatorInterfaceName<precon_base> + { + public: + Creator(int l0) + { l.push_back(l0); }; + + Creator(int l0, int l1) + { l.push_back(l0); l.push_back(l1); }; + + Creator(int l0, int l1, int l2) + { l.push_back(l0); l.push_back(l1); l.push_back(l2); }; + + Creator(const std::vector<int>& l) : l(l) {} + + virtual ~Creator() {} + + precon_base* create() { + return new self(l); + } + private: + std::vector<int> l; + }; + + /// Constructor + TriangularPreconditioner(const std::vector<int>& parts_) + : super(parts_) + { } + + virtual ~TriangularPreconditioner() {} + + /// Apply the preconditioners block-wise + /** + * solve Px = b, with + * P = diag(P1, P2, ...) + **/ + void solve(const MTLTypes::MTLVector& b, MTLTypes::MTLVector& x) const override + { FUNCNAME("CombinedPreconditioner::solve()"); + + x.change_dim(num_rows(b)); + y.change_dim(num_rows(b)); + c.change_dim(num_rows(b)); + set_to_zero(c); + + for (size_t i = super::precon.size()-1; i >= 0; i--) { + MTLTypes::MTLVector y_i(b[super::rows[i]]); + if (i < super::precon.size()-1) + y_i -= y[super::rows[i]]; + + MTLTypes::MTLVector x_i(x[super::rows[i]]); + super::precon[i]->solve(y_i, x_i); + + if (i > 0) { + c[super::rows[i]] = x_i; + y = (*super::fullMatrix) * c; + } + } + } + + private: + mutable MTLTypes::MTLVector y; + mutable MTLTypes::MTLVector c; + }; + +} // end namespace AMDiS + +#endif // AMDIS_COMBINED_PRECONDITIONER_H diff --git a/AMDiS/src/solver/UmfPackSolver.h b/AMDiS/src/solver/UmfPackSolver.h index 9c6818455d558a22cced06b7986c5738522a5611..81c8784d076ae5247c53d38ce384414764759daf 100644 --- a/AMDiS/src/solver/UmfPackSolver.h +++ b/AMDiS/src/solver/UmfPackSolver.h @@ -51,7 +51,7 @@ namespace AMDiS { } /// Implementation of \ref MTL4Runner::init() - void init(const typename super::BlockMatrix& A, const MatrixType& fullMatrix) override + void init(const SolverMatrix<Matrix<DOFMatrix*> >& A, const MatrixType& fullMatrix) override { if (solver != nullptr) { delete solver; diff --git a/AMDiS/src/solver/itl/block_diagonal.hpp b/AMDiS/src/solver/itl/block_diagonal.hpp new file mode 100644 index 0000000000000000000000000000000000000000..71d8b92873328e08f96494c53082ebafd351ca83 --- /dev/null +++ b/AMDiS/src/solver/itl/block_diagonal.hpp @@ -0,0 +1,77 @@ +#ifndef ITL_PC_BLOCK_DIAGONAL_INCLUDE +#define ITL_PC_BLOCK_DIAGONAL_INCLUDE + +#include <boost/numeric/itl/pc/diagonal.hpp> + +#include "solver/BlockMTLMatrix.h" + +namespace itl { namespace pc { + +/// Diagonal Preconditioner +template <> +class diagonal<AMDiS::BlockMTLMatrix, mtl::Collection<AMDiS::BlockMTLMatrix>::value_type> +{ + public: + typedef mtl::Collection<AMDiS::BlockMTLMatrix>::value_type Value; + typedef Value value_type; + typedef mtl::Collection<AMDiS::BlockMTLMatrix>::size_type size_type; + typedef diagonal self; + + /// Constructor takes matrix reference + explicit diagonal(const AMDiS::BlockMTLMatrix& A) : inv_diag(num_rows(A)) + { + MTL_THROW_IF(num_rows(A) != num_cols(A), mtl::matrix_not_square()); + using math::reciprocal; + + for (size_t i = 0; i < A.n_rows; i++) + inv_diag[A.getRowRange(i)] = mtl::matrix::diagonal(A.getSubMatrix(i,i)); + + for (size_type i= 0; i < num_rows(A); ++i) + inv_diag[i]= reciprocal(inv_diag[i]); + } + + /// Member function solve, better use free function solve + template <typename Vector> + Vector solve(const Vector& x) const + { + Vector y(resource(x)); + solve(x, y); + return y; + } + + template <typename VectorIn, typename VectorOut> + void solve(const VectorIn& x, VectorOut& y) const + { + y.checked_change_resource(x); + MTL_THROW_IF(size(x) != size(inv_diag), mtl::incompatible_size()); + for (size_type i= 0; i < size(inv_diag); ++i) + y[i]= inv_diag[i] * x[i]; + } + + /// Member function for solving adjoint problem, better use free function adjoint_solve + template <typename Vector> + Vector adjoint_solve(const Vector& x) const + { + Vector y(resource(x)); + adjoint_solve(x, y); + return y; + } + + template <typename VectorIn, typename VectorOut> + void adjoint_solve(const VectorIn& x, VectorOut& y) const + { + using mtl::conj; + y.checked_change_resource(x); + MTL_THROW_IF(size(x) != size(inv_diag), mtl::incompatible_size()); + for (size_type i= 0; i < size(inv_diag); ++i) + y[i]= conj(inv_diag[i]) * x[i]; + } + + protected: + mtl::vector::dense_vector<value_type> inv_diag; +}; + + +}} // namespace itl::pc + +#endif // ITL_PC_DIAGONAL_INCLUDE diff --git a/AMDiS/src/traits/category.hpp b/AMDiS/src/traits/category.hpp index e52059e986abb76d13dbc640d1ef55c1af08d6dc..be27b0a00de9e667a1d834c2ed16f4be944487df 100644 --- a/AMDiS/src/traits/category.hpp +++ b/AMDiS/src/traits/category.hpp @@ -30,6 +30,7 @@ #include "types.hpp" #include "DOFMatrix.h" +#include "solver/BlockMTLMatrix.h" #include <boost/mpl/if.hpp> #include <boost/mpl/or.hpp> @@ -206,6 +207,14 @@ namespace AMDiS typedef AMDiS::DOFMatrix::size_type size_type; }; + template <> + struct category< AMDiS::BlockMTLMatrix > + { + typedef tag::matrix tag; + typedef AMDiS::DOFMatrix::value_type value_type; + typedef AMDiS::DOFMatrix::size_type size_type; + }; + template < class Matrix > struct category< AMDiS::SolverMatrix<Matrix> > { diff --git a/AMDiS/src/traits/num_cols.hpp b/AMDiS/src/traits/num_cols.hpp index 08f44137280cdff8ab04eb0e32691f5003caaa15..178de24c89acd2de797b1a19d0648db87191221f 100644 --- a/AMDiS/src/traits/num_cols.hpp +++ b/AMDiS/src/traits/num_cols.hpp @@ -139,6 +139,14 @@ namespace AMDiS typedef category< AMDiS::DOFMatrix >::size_type type; type operator()(const AMDiS::DOFMatrix& v) const { return mtl::matrix::num_cols(v.getBaseMatrix()); } }; + + /// size implementation for AMDiS::BlockMTLMatrix + template <> + struct num_cols< AMDiS::BlockMTLMatrix > + { + typedef category< AMDiS::BlockMTLMatrix >::size_type type; + type operator()(const AMDiS::BlockMTLMatrix& M) const { return M.m; } + }; // === multi-vector or multi-multi-vector === diff --git a/AMDiS/src/traits/num_rows.hpp b/AMDiS/src/traits/num_rows.hpp index e1372215957bddec352da24ad09d91d88113f1c8..e244582b87ba756fff04169f9d5be2a70344082f 100644 --- a/AMDiS/src/traits/num_rows.hpp +++ b/AMDiS/src/traits/num_rows.hpp @@ -139,6 +139,14 @@ namespace AMDiS typedef category< AMDiS::DOFMatrix >::size_type type; type operator()(const AMDiS::DOFMatrix& v) const { return mtl::matrix::num_rows(v.getBaseMatrix()); } }; + + /// size implementation for AMDiS::BlockMTLMatrix + template <> + struct num_rows< AMDiS::BlockMTLMatrix > + { + typedef category< AMDiS::BlockMTLMatrix >::size_type type; + type operator()(const AMDiS::BlockMTLMatrix& M) const { return M.n; } + }; // === multi-vector or multi-multi-vector === diff --git a/AMDiS/src/traits/size.hpp b/AMDiS/src/traits/size.hpp index 503bc6f7b03be7f7e8136d94b180f074900e6447..7d6e1b8148986b1548f79c9b4c46760edcd18abe 100644 --- a/AMDiS/src/traits/size.hpp +++ b/AMDiS/src/traits/size.hpp @@ -139,6 +139,14 @@ namespace AMDiS typedef category< AMDiS::DOFMatrix >::size_type type; type operator()(const AMDiS::DOFMatrix& v) const { return mtl::matrix::size(v.getBaseMatrix()); } }; + + /// size implementation for AMDiS::BlockMTLMatrix + template <> + struct size< AMDiS::BlockMTLMatrix > + { + typedef category< AMDiS::BlockMTLMatrix >::size_type type; + type operator()(const AMDiS::BlockMTLMatrix& M) const { return (M.n) * (M.m); } + }; // === multi-vector or multi-matrix === diff --git a/AMDiS/src/utility/calculate_nnz.hpp b/AMDiS/src/utility/calculate_nnz.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4d456739cc4931517bc8d0db447bcd93c014c479 --- /dev/null +++ b/AMDiS/src/utility/calculate_nnz.hpp @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * AMDiS - Adaptive multidimensional simulations + * + * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved. + * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis + * + * Authors: + * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * + * This file is part of AMDiS + * + * See also license.opensource.txt in the distribution. + * + ******************************************************************************/ + + + +/** \file calculate_nnz.hpp */ + +#ifndef AMDIS_UTILITY_CALCULATE_NNZ_HPP +#define AMDIS_UTILITY_CALCULATE_NNZ_HPP + +namespace AMDiS { + + inline void calculate_nnz(const DOFMatrix& matrix, std::vector<size_t>& nnz_per_row) + { + std::vector<std::set<DegreeOfFreefom> > nnz(nnz_per_row.size()); + std::vector<DegreeOfFreedom> rowIndices, colIndices; + const FiniteElemSpace* rowFeSpace = matrix.getRowFeSpace(), + colFeSpace = matrix.getColFeSpace(); + + TraverseStack stack; + ElInfo *elInfo = stack.traverseFirst(rowFeSpace->getMesh(), -1, Mesh::CALL_LEAF_EL); + while (elInfo) { + rowFeSpace->getBasisFcts()->getLocalIndices(elInfo->getElement(), + rowFeSpace->getAdmin(), + rowIndices); + if (rowFeSpace == colFeSpace) { + colIndices = rowIndices; + } else { + colFeSpace->getBasisFcts()->getLocalIndices(elInfo->getElement(), + colFeSpace->getAdmin(), + colIndices); + } + + for (size_t r = 0; r < rowIndices.size(); r++) + for (size_t c = 0; c < rowIndices.size(); c++) + nnz[rowIndices[r]].insert(colIndices[c]); + + elInfo = stack.traverseNext(elInfo); + } + + for (size_t r = 0; r < nnz.size(); r++) + nnz_per_row[r] = nnz[r].size(); + } + +} // end namspace AMDiS + +#endif \ No newline at end of file diff --git a/AMDiS/src/utility/is_symmetric.hpp b/AMDiS/src/utility/is_symmetric.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8f030ccf85be33b9206c2f5e30ee6cd52a7eccc8 --- /dev/null +++ b/AMDiS/src/utility/is_symmetric.hpp @@ -0,0 +1,53 @@ +/****************************************************************************** + * + * AMDiS - Adaptive multidimensional simulations + * + * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved. + * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis + * + * Authors: + * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * + * This file is part of AMDiS + * + * See also license.opensource.txt in the distribution. + * + ******************************************************************************/ + + + +/** \file is_symmetric.hpp */ + +#ifndef AMDIS_UTILITY_IS_SYMMETRIC_HPP +#define AMDIS_UTILITY_IS_SYMMETRIC_HPP + +namespace AMDiS { + + template< class Matrix > + inline bool is_symmetric(const Matrix& matrix, double tol = 1.e-5) + { + using mtl::tag::major; using mtl::tag::nz; using mtl::begin; using mtl::end; + namespace traits= mtl::traits; + + traits::row<Matrix>::type row(matrix); + traits::col<Matrix>::type col(matrix); + traits::const_value<Matrix>::type value(matrix); + + typedef traits::range_generator<major, Matrix>::type cursor_type; + typedef traits::range_generator<nz, cursor_type>::type icursor_type; + + for (cursor_type cursor = begin<major>(matrix), cend = end<major>(matrix); cursor != cend; ++cursor) + for (icursor_type icursor = begin<nz>(cursor), icend = end<nz>(cursor); icursor != icend; ++icursor) + // Compare each non-zero entry with its transposed + if (abs(value(*icursor) - matrix[col(*icursor)][row(*icursor)]) > tol) + return false; + return true; + } + +} // end namspace AMDiS + +#endif \ No newline at end of file