From 757ba5c5fe8c515f63f8b8a198f562739a857cba Mon Sep 17 00:00:00 2001 From: Thomas Witkowski <thomas.witkowski@gmx.de> Date: Sun, 26 Jun 2011 09:10:12 +0000 Subject: [PATCH] Added first try of nonlinear solvers. --- AMDiS/CMakeLists.txt | 2 + AMDiS/src/OEMSolver.h | 6 +- AMDiS/src/nonlin/NonLinSolver.h | 185 ++++++++++++++++++++++++++++++ AMDiS/src/nonlin/NonLinUpdater.cc | 104 +++++++++++++++++ AMDiS/src/nonlin/NonLinUpdater.h | 52 +++++++++ AMDiS/src/nonlin/ProblemNonLin.cc | 124 ++++++++++++++++++++ AMDiS/src/nonlin/ProblemNonLin.h | 158 +++++++++++++++++++++++++ 7 files changed, 628 insertions(+), 3 deletions(-) create mode 100644 AMDiS/src/nonlin/NonLinSolver.h create mode 100644 AMDiS/src/nonlin/NonLinUpdater.cc create mode 100644 AMDiS/src/nonlin/NonLinUpdater.h create mode 100644 AMDiS/src/nonlin/ProblemNonLin.cc create mode 100644 AMDiS/src/nonlin/ProblemNonLin.h diff --git a/AMDiS/CMakeLists.txt b/AMDiS/CMakeLists.txt index a238f467..16e74b64 100644 --- a/AMDiS/CMakeLists.txt +++ b/AMDiS/CMakeLists.txt @@ -145,6 +145,8 @@ SET(AMDIS_SRC ${SOURCE_DIR}/AdaptBase.cc ${SOURCE_DIR}/io/ValueReader.cc ${SOURCE_DIR}/io/ValueWriter.cc ${SOURCE_DIR}/io/VtkWriter.cc + ${SOURCE_DIR}/nonlin/NonLinUpdater.cc + ${SOURCE_DIR}/nonlin/ProblemNonLin.cc ${SOURCE_DIR}/parallel/InteriorBoundary.cc ${SOURCE_DIR}/time/RosenbrockAdaptInstationary.cc ${SOURCE_DIR}/time/RosenbrockMethod.cc diff --git a/AMDiS/src/OEMSolver.h b/AMDiS/src/OEMSolver.h index 329bad38..37a7df8e 100644 --- a/AMDiS/src/OEMSolver.h +++ b/AMDiS/src/OEMSolver.h @@ -98,9 +98,9 @@ namespace AMDiS { SystemVector& b, VectorialMapper&) = 0; - inline int solveSystem(const SolverMatrix< Matrix< DOFMatrix* > >& A, - SystemVector& x, - SystemVector& b) + inline int solveSystem(const SolverMatrix<Matrix<DOFMatrix*> >& A, + SystemVector& x, + SystemVector& b) { VectorialMapper mapper(A); return solveSystem(A, x, b, mapper); diff --git a/AMDiS/src/nonlin/NonLinSolver.h b/AMDiS/src/nonlin/NonLinSolver.h new file mode 100644 index 00000000..671a1d1c --- /dev/null +++ b/AMDiS/src/nonlin/NonLinSolver.h @@ -0,0 +1,185 @@ +// ============================================================================ +// == == +// == AMDiS - Adaptive multidimensional simulations == +// == == +// == http://www.amdis-fem.org == +// == == +// ============================================================================ +// +// Software License for AMDiS +// +// Copyright (c) 2010 Dresden University of Technology +// All rights reserved. +// Authors: Simon Vey, Thomas Witkowski et al. +// +// This file is part of AMDiS +// +// See also license.opensource.txt in the distribution. + + + +/** \file NonLinSolver.h */ + +#ifndef AMDIS_NONLINSOLVER_H +#define AMDIS_NONLINSOLVER_H + +#include <string> + +#include "Global.h" +#include "CreatorInterface.h" +#include "MatrixVector.h" +#include "DOFMatrix.h" +#include "OEMSolver.h" + +namespace AMDiS { + + /** + * \ingroup Solver + * + * \brief + * Pure virtual base class for Newton, NewtonS and Banach which all + * solves non linear equation systems. Sub classes must implement the methods + * \ref init, \ref exit and \ref nlsolve. + */ + class NonLinSolver + { + public: + /** \brief + * constructor. + * \param name name of this solver + */ + NonLinSolver(const std::string &name_, + OEMSolver *solver, + NonLinUpdater *updater) + : name(name_), + linSolver(solver), + nonLinUpdater(updater), + tolerance(1.e-4), + maxIter(50), + info(8), + initial_residual(0.0), + residual(0.0), + usedNorm(NO_NORM) + { + Parameters::get(name + "->tolerance", tolerance); + Parameters::get(name + "->max iteration", maxIter); + Parameters::get(name + "->info", info); + Parameters::get(name + "->norm", usedNorm); + } + + /** \brief + * destructor + */ + virtual ~NonLinSolver() {} + + /** \brief + * solves the non linear system. Uses sub class methods + */ + inline int solve(SolverMatrix<Matrix<DOFMatrix*> >& mat, + SystemVector &x, SystemVector &rhs) + { + init(); + int result = nlsolve(mat, x, rhs); + exit(); + return result; + } + + inline void setTolerance(double tol) + { + tolerance = tol; + } + + inline double getTolerance() + { + return tolerance; + } + + inline OEMSolver* getLinearSolver() + { + return linSolver; + } + + inline void setNonLinUpdater(NonLinUpdater *up) + { + nonLinUpdater = up; + } + + inline NonLinUpdater *getNonLinUpdater() + { + return nonLinUpdater; + } + + protected: + /** \brief + * Allocates needed memory. Must be overriden in sub classes. + */ + virtual void init() = 0; + + /** \brief + * Solves the non linear system. Must be overriden in sub classes. + */ + virtual int nlsolve(SolverMatrix<Matrix<DOFMatrix*> >& matVec, + SystemVector& x, SystemVector& rhs) = 0; + + /** \brief + * Frees needed memory. Must be overriden in sub classes. + */ + virtual void exit() = 0; + + virtual int solveLinearSystem(SolverMatrix<Matrix<DOFMatrix*> >& mat, + SystemVector &fh, SystemVector &x) + { + FUNCNAME("NonLinSolver::solveLinearSystem()"); + TEST_EXIT(linSolver)("no solver\n"); + return linSolver->solveSystem(mat, x, fh); + } + + protected: + std::string name; /**< \brief name of the solver */ + OEMSolver *linSolver; /**< \brief linear solver*/ + NonLinUpdater *nonLinUpdater; /**< \brief non linear updater */ + double tolerance; /**< \brief solver tolerance */ + int maxIter; /**< \brief maximal # of iterations */ + int info; /**< \brief info level */ + double initial_residual; /**< \brief initial residual */ + double residual; /**< \brief current residual */ + Norm usedNorm; /**< \brief used norm */ + }; + + // ============================================================================ + // ===== class NonLinSolverCreator ============================================ + // ============================================================================ + + /** \brief + * Interface for creators of concrete NonLinSolvers. + */ + class NonLinSolverCreator : public CreatorInterface<NonLinSolver> + { + public: + virtual ~NonLinSolverCreator() {} + + void setName(std::string name_) + { + name = name_; + } + + void setLinearSolver(OEMSolver *solver) + { + linearSolver = solver; + } + + void setNonLinUpdater(NonLinUpdater *updater) + { + nonLinUpdater = updater; + } + + protected: + std::string name; + OEMSolver *linearSolver; + NonLinUpdater *nonLinUpdater; + }; + +} + +#endif // AMDIS_NONLINSOLVER_H + diff --git a/AMDiS/src/nonlin/NonLinUpdater.cc b/AMDiS/src/nonlin/NonLinUpdater.cc new file mode 100644 index 00000000..451c70a4 --- /dev/null +++ b/AMDiS/src/nonlin/NonLinUpdater.cc @@ -0,0 +1,104 @@ +// +// Software License for AMDiS +// +// Copyright (c) 2010 Dresden University of Technology +// All rights reserved. +// Authors: Simon Vey, Thomas Witkowski et al. +// +// This file is part of AMDiS +// +// See also license.opensource.txt in the distribution. + + +#include "NonLinUpdater.h" +#include "Global.h" +#include "DOFMatrix.h" +#include "DOFVector.h" +#include "Traverse.h" +#include "ElInfo.h" +#include "Flag.h" +#include "Operator.h" +#include "FiniteElemSpace.h" +#include "BasisFunction.h" +#include "BoundaryManager.h" + +namespace AMDiS { + + void NonLinUpdater::update(bool updateDF, SystemVector *F) + { + FUNCNAME("NonLinUpdater::update()"); + + TraverseStack stack; + ElInfo *el_info; + Flag fill_flag; + + TEST_EXIT(F || df)("neither F nor df are set\n"); + + if (!updateDF && (F == NULL)) { + WARNING("No RHS vector and no update for system matrix! Updater does nothing!\n"); + return; + } + + int size = df->getNumRows(); + + const FiniteElemSpace *feSpace = + F ? + F->getDOFVector(0)->getFeSpace() : + (*df)[0][0]->getFeSpace(); + + if (updateDF) { + TEST_EXIT(df)("df not set but update tried!\n"); + + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + if ((*df)[i][j]) { + (*df)[i][j]->clear(); + } + } + } + } + + BasisFunction *basFcts = const_cast<BasisFunction*>(feSpace->getBasisFcts()); + + if (F) { + for (int i = 0; i < size; i++) { + F->getDOFVector(i)->set(0.0); + } + } + + fill_flag = + Mesh::CALL_LEAF_EL| + Mesh::FILL_COORDS| + Mesh::FILL_BOUND| + Mesh::FILL_DET| + Mesh::FILL_GRD_LAMBDA; + + BoundaryType *bound = new BoundaryType[basFcts->getNumber()]; + + el_info = stack.traverseFirst(feSpace->getMesh(), -1, fill_flag); + while (el_info) { + basFcts->getBound(el_info, bound); + + if (updateDF) { + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + if ((*df)[i][j]) { + (*df)[i][j]->assemble(1.0, el_info, bound); + } + } + } + } + + if (F) { + for(int i = 0; i < size; i++) { + F->getDOFVector(i)->assemble(1.0, el_info, bound); + } + } + + el_info = stack.traverseNext(el_info); + } + + delete [] bound; + } + +} diff --git a/AMDiS/src/nonlin/NonLinUpdater.h b/AMDiS/src/nonlin/NonLinUpdater.h new file mode 100644 index 00000000..3092845e --- /dev/null +++ b/AMDiS/src/nonlin/NonLinUpdater.h @@ -0,0 +1,52 @@ +// ============================================================================ +// == == +// == AMDiS - Adaptive multidimensional simulations == +// == == +// == http://www.amdis-fem.org == +// == == +// ============================================================================ +// +// Software License for AMDiS +// +// Copyright (c) 2010 Dresden University of Technology +// All rights reserved. +// Authors: Simon Vey, Thomas Witkowski et al. +// +// This file is part of AMDiS +// +// See also license.opensource.txt in the distribution. + + + +/** \file NonLinUpdater.h */ + +#ifndef AMDIS_NONLINAPDATOR_H +#define AMDIS_NONLINAPDATOR_H + +#include "SystemVector.h" + +namespace AMDiS { + + /** \brief + * Used in non linear solvers for matrix and vector assemblage. + */ + class NonLinUpdater + { + public: + NonLinUpdater(Matrix<DOFMatrix*> *m) + : df(m) + {} + + ~NonLinUpdater() + {} + + void update(bool updateDF, SystemVector *F); + + protected: + /// Matrix to be updated. + Matrix<DOFMatrix*> *df; + }; + +} + +#endif diff --git a/AMDiS/src/nonlin/ProblemNonLin.cc b/AMDiS/src/nonlin/ProblemNonLin.cc new file mode 100644 index 00000000..1c66a269 --- /dev/null +++ b/AMDiS/src/nonlin/ProblemNonLin.cc @@ -0,0 +1,124 @@ +// +// Software License for AMDiS +// +// Copyright (c) 2010 Dresden University of Technology +// All rights reserved. +// Authors: Simon Vey, Thomas Witkowski et al. +// +// This file is part of AMDiS +// +// See also license.opensource.txt in the distribution. + + +#include "ProblemNonLin.h" +#include "NonLinSolver.h" +#include "CreatorMap.h" +#include "NonLinUpdater.h" +#include "Traverse.h" +#include "AdaptInfo.h" + +namespace AMDiS { + + void ProblemNonLin::initialize(Flag initFlag, + ProblemStat *adoptProblem /*= NULL*/, + Flag adoptFlag /*= INIT_NOTHING*/) + { + ProblemStat::initialize(initFlag, adoptProblem, adoptFlag); + + // === create Updater === + if (updater_) { + WARNING("updater already created\n"); + } else { + if (initFlag.isSet(INIT_UPDATER) || + ((!adoptFlag.isSet(INIT_UPDATER)) && initFlag.isSet(INIT_NONLIN_SOLVER))) { + createUpdater(); + } + + if (adoptProblem && + (adoptFlag.isSet(INIT_UPDATER) || + ((!initFlag.isSet(INIT_UPDATER))&& adoptFlag.isSet(INIT_NONLIN_SOLVER)))) { + TEST_EXIT(updater_==NULL)("updater already created\n"); + updater_ = dynamic_cast<ProblemNonLin*>(adoptProblem)->getUpdater(); + } + } + + if (updater_ == NULL) + WARNING("no updater created\n"); + + // === create nonlinear solver === + if (nonLinSolver_) { + WARNING("nonlinear solver already created\n"); + } else { + if (initFlag.isSet(INIT_NONLIN_SOLVER)) + createNonLinSolver(); + + if (adoptProblem && adoptFlag.isSet(INIT_NONLIN_SOLVER)) { + TEST_EXIT(nonLinSolver_ == NULL)("nonlinear solver already created\n"); + nonLinSolver_ = dynamic_cast<ProblemNonLin*>(adoptProblem)->getNonLinSolver(); + } + } + + if (nonLinSolver_ == NULL) + WARNING("no nonlinear solver created\n"); + } + + + void ProblemNonLin::createNonLinSolver() + { + // create non-linear solver + std::string nonLinSolverType("no"); + Parameters::get(name + "->nonlin solver", nonLinSolverType); + + NonLinSolverCreator *nonLinSolverCreator = + dynamic_cast<NonLinSolverCreator*>(CreatorMap<NonLinSolver>::getCreator(nonLinSolverType)); + + nonLinSolverCreator->setLinearSolver(solver); + nonLinSolverCreator->setName(name + "->nonlin solver"); + nonLinSolverCreator->setNonLinUpdater(updater_); + nonLinSolver_ = nonLinSolverCreator->create(); + } + + + void ProblemNonLin::solve(AdaptInfo *adaptInfo) + { + TEST_EXIT(nonLinSolver_)("no non-linear solver!\n"); + nonLinSolver_->solve(solverMatrix, *solution, *rhs); + } + + + void ProblemNonLin::buildAfterCoarsen(AdaptInfo *adaptInfo, Flag, bool, bool) + { + FUNCNAME("ProblemNonLin::buildAfterCoarsen()"); + int nMeshes = static_cast<int>(meshes.size()); + + for (int i = 0; i < nMeshes; i++) + meshes[i]->dofCompress(); + + for (int i = 0; i < nComponents; i++) { + MSG("%d DOFs for %s\n", + componentSpaces[i]->getAdmin()->getUsedSize(), + componentSpaces[i]->getName().c_str()); + } + + TraverseStack stack; + ElInfo *elInfo; + + // for all elements ... + for (int i = 0; i < nComponents; i++) { + elInfo = stack.traverseFirst(componentMeshes[i], -1, + Mesh::CALL_LEAF_EL | + Mesh::FILL_BOUND | + Mesh::FILL_COORDS | + Mesh::FILL_DET | + Mesh::FILL_GRD_LAMBDA); + while (elInfo) { + if (solution->getDOFVector(i)->getBoundaryManager()) { + solution->getDOFVector(i)-> + getBoundaryManager()->fillBoundaryConditions(elInfo, solution->getDOFVector(i)); + } + elInfo = stack.traverseNext(elInfo); + } + } + } + +} diff --git a/AMDiS/src/nonlin/ProblemNonLin.h b/AMDiS/src/nonlin/ProblemNonLin.h new file mode 100644 index 00000000..ded55285 --- /dev/null +++ b/AMDiS/src/nonlin/ProblemNonLin.h @@ -0,0 +1,158 @@ +// ============================================================================ +// == == +// == AMDiS - Adaptive multidimensional simulations == +// == == +// == http://www.amdis-fem.org == +// == == +// ============================================================================ +// +// Software License for AMDiS +// +// Copyright (c) 2010 Dresden University of Technology +// All rights reserved. +// Authors: Simon Vey, Thomas Witkowski et al. +// +// This file is part of AMDiS +// +// See also license.opensource.txt in the distribution. + + + +/** \file ProblemNonLin.h */ + +#ifndef AMDIS_PROBLEMNONLIN_H_ +#define AMDIS_PROBLEMNONLIN_H_ + +#include "ProblemStat.h" +#include "NonLinUpdater.h" +#include "NonLinSolver.h" +#include "DOFVector.h" +#include "SystemVector.h" +#include "MatrixVector.h" + +namespace AMDiS { + + /** + * \ingroup Problem + * + * \brief + * Standard implementation for a vector valued non linear problem. + */ + class ProblemNonLin : public ProblemStat + { + public: + /// Constructs a ProblemNonLin with given name. + ProblemNonLin(const std::string& name_) + : ProblemStat(name_.c_str()), + nonLinSolver_(NULL), + updater_(NULL) + { + u0_.resize(nComponents); + u0_.set(NULL); + } + + /** \brief + * Sets \ref u0_ and interpolates it to \ref solution_. + */ + inline void setU0(AbstractFunction<double, WorldVector<double> > *u0Fct, + int index) + { + FUNCNAME("ProblemNonLinVec::setU0()"); + TEST_EXIT(index < nComponents)("invalid index\n"); + u0_[index] = u0Fct; + solution->getDOFVector(index)->interpol(u0Fct); + } + + /** \brief + * Destructor. + */ + virtual ~ProblemNonLin() {} + + /** \brief + * Initialisation of the problem. + */ + virtual void initialize(Flag initFlag, + ProblemStat *adoptProblem = NULL, + Flag adoptFlag = INIT_NOTHING); + + /** \brief + * Used in \ref initialize(). + */ + virtual void createUpdater() + { + updater_ = new NonLinUpdater(systemMatrix); + } + + /** \brief + * Used in \ref initialize(). + */ + virtual void createNonLinSolver(); + + /** \brief + * Overrides ProblemVec::solve(). Uses the non linear solver + * \ref nonLinSolver_. + */ + virtual void solve(AdaptInfo *adaptInfo); + + /** \brief + * Overrides Problem::buildAfterCoarsen(). Sets dirichlet boundaries + * in \ref A_ and \ref rhs_. + */ + virtual void buildAfterCoarsen(AdaptInfo *adaptInfo, Flag, + bool assembleMatrix = true, + bool assembleVector = true); + + /** \brief + * Returns /ref nonLinSolver_. + */ + inline NonLinSolver *getNonLinSolver() + { + return nonLinSolver_; + } + + /** \brief + * Returns \ref updater. + */ + inline NonLinUpdater* getUpdater() + { + return updater_; + } + + /** \brief + * Sets \ref nonLinSolver_. + */ + inline void setNonLinSolver(NonLinSolver *nonLinSolver) + { + nonLinSolver_ = nonLinSolver; + } + + /** \brief + * Sets \ref updater. + */ + inline void setUpdater(NonLinUpdater *updater) + { + updater_ = updater; + } + + + protected: + /** \brief + * Initial guess for the solution. + */ + Vector<AbstractFunction<double, WorldVector<double> >*> u0_; + + /** \brief + * Non linear solver. Used in \ref solve(). + */ + NonLinSolver *nonLinSolver_; + + /** \brief + * Updator + */ + NonLinUpdater *updater_; + }; + +} + +#endif + -- GitLab