From 238545729034208bb372afc3976d57cd7100b98a Mon Sep 17 00:00:00 2001 From: Bernd Flemisch <bernd@iws.uni-stuttgart.de> Date: Fri, 30 Nov 2012 12:30:46 +0000 Subject: [PATCH] implicit branch: unify assemblers. git-svn-id: svn://svn.iws.uni-stuttgart.de/DUMUX/dumux/branches/implicit@9739 2fb0f335-1f38-0410-981e-8018bf24f1b0 --- dumux/implicit/box/boxassembler.hh | 668 +++------------------ dumux/implicit/cellcentered/ccassembler.hh | 557 +++-------------- dumux/implicit/common/implicitassembler.hh | 405 ++----------- 3 files changed, 215 insertions(+), 1415 deletions(-) diff --git a/dumux/implicit/box/boxassembler.hh b/dumux/implicit/box/boxassembler.hh index d585d360a2..6bbcebb9f7 100644 --- a/dumux/implicit/box/boxassembler.hh +++ b/dumux/implicit/box/boxassembler.hh @@ -24,11 +24,7 @@ #ifndef DUMUX_BOX_ASSEMBLER_HH #define DUMUX_BOX_ASSEMBLER_HH -#include <dune/grid/common/gridenums.hh> - -#include <dumux/implicit/box/boxproperties.hh> -#include <dumux/linear/vertexborderlistfromgrid.hh> -#include <dumux/linear/foreignoverlapfrombcrsmatrix.hh> +#include <dumux/implicit/common/implicitassembler.hh> #include <dumux/parallel/vertexhandles.hh> namespace Dumux { @@ -37,282 +33,26 @@ namespace Dumux { * \brief An assembler for the global Jacobian matrix for models using the box discretization. */ template<class TypeTag> -class BoxAssembler +class BoxAssembler : public ImplicitAssembler<TypeTag> { - typedef typename GET_PROP_TYPE(TypeTag, Model) Model; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef ImplicitAssembler<TypeTag> ParentType; + friend class ImplicitAssembler<TypeTag>; typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; - typedef typename GET_PROP_TYPE(TypeTag, ElementMapper) ElementMapper; - - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - - enum{ dim = GridView::dimension }; typedef typename GridView::template Codim<0>::Entity Element; typedef typename GridView::template Codim<0>::Iterator ElementIterator; + enum{ dim = GridView::dimension }; typedef typename GridView::template Codim<dim>::EntityPointer VertexPointer; - enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; - typedef Dune::FieldMatrix<Scalar, numEq, numEq> MatrixBlock; - typedef Dune::FieldVector<Scalar, numEq> VectorBlock; - +public: + BoxAssembler(): ParentType() {} + +private: // copying the jacobian assembler is not a good idea BoxAssembler(const BoxAssembler &); -public: - /*! - * \brief The colors of elements and vertices required for partial - * Jacobian reassembly. - */ - enum EntityColor { - /*! - * Vertex/element that needs to be reassembled because some - * relative error is above the tolerance - */ - Red = 0, - - /*! - * Vertex/element that needs to be reassembled because a - * neighboring element/vertex is red - */ - Yellow = 1, - - /*! - * Yellow vertex has only non-green neighbor elements. - * - * This means that its relative error is below the tolerance, - * but its defect can be linearized without any additional - * cost. This is just an "internal" color which is not used - * ouside of the jacobian assembler. - */ - Orange = 2, - - /*! - * Vertex/element that does not need to be reassembled - */ - Green = 3 - }; - - BoxAssembler() - { - problemPtr_ = 0; - matrix_ = 0; - - // set reassemble accuracy to 0, so that if partial reassembly - // of the jacobian matrix is disabled, the reassemble accuracy - // is always smaller than the current relative tolerance - reassembleAccuracy_ = 0.0; - } - - ~BoxAssembler() - { - delete matrix_; - } - - /*! - * \brief Initialize the jacobian assembler. - * - * At this point we can assume that all objects in the problem and - * the model have been allocated. We can not assume that they are - * fully initialized, though. - * - * \param problem The problem object - */ - void init(Problem& problem) - { - problemPtr_ = &problem; - - // initialize the BCRS matrix - createMatrix_(); - - // initialize the jacobian matrix and the right hand side - // vector - *matrix_ = 0; - reuseMatrix_ = false; - - int numVerts = gridView_().size(dim); - int numElems = gridView_().size(0); - - residual_.resize(numVerts); - - // initialize the storage part of the Jacobian matrix. Since - // we only need this if Jacobian matrix recycling is enabled, - // we do not waste space if it is disabled - if (enableJacobianRecycling_()) { - storageJacobian_.resize(numVerts); - storageTerm_.resize(numVerts); - } - - if (gridView_().comm().size() > 1) - totalElems_ = gridView_().comm().sum(numElems); - else - totalElems_ = numElems; - - // initialize data needed for partial reassembly - if (enablePartialReassemble_()) { - vertexColor_.resize(numVerts); - vertexDelta_.resize(numVerts); - elementColor_.resize(numElems); - } - reassembleAll(); - } - - /*! - * \brief Assemble the global Jacobian of the residual and the residual for the current solution. - * - * The current state of affairs (esp. the previous and the current - * solutions) is represented by the model object. - */ - void assemble() - { - bool printReassembleStatistics = enablePartialReassemble_() && !reuseMatrix_; - int succeeded; - try { - assemble_(); - succeeded = 1; - if (gridView_().comm().size() > 1) - succeeded = gridView_().comm().min(succeeded); - } - catch (Dumux::NumericalProblem &e) - { - std::cout << "rank " << problem_().gridView().comm().rank() - << " caught an exception while assembling:" << e.what() - << "\n"; - succeeded = 0; - if (gridView_().comm().size() > 1) - succeeded = gridView_().comm().min(succeeded); - } - - if (!succeeded) { - DUNE_THROW(NumericalProblem, - "A process did not succeed in linearizing the system"); - } - - if (printReassembleStatistics) - { - if (gridView_().comm().size() > 1) - { - greenElems_ = gridView_().comm().sum(greenElems_); - reassembleAccuracy_ = gridView_().comm().max(nextReassembleAccuracy_); - } - else - { - reassembleAccuracy_ = nextReassembleAccuracy_; - } - - problem_().newtonController().endIterMsg() - << ", reassembled " - << totalElems_ - greenElems_ << "/" << totalElems_ - << " (" << 100*Scalar(totalElems_ - greenElems_)/totalElems_ << "%) elems @accuracy=" - << reassembleAccuracy_; - } - - // reset all vertex colors to green - for (unsigned int i = 0; i < vertexColor_.size(); ++i) { - vertexColor_[i] = Green; - } - } - - /*! - * \brief If Jacobian matrix recycling is enabled, this method - * specifies whether the next call to assemble() just - * rescales the storage term or does a full reassembly - * - * \param yesno If true, only rescale; else do full Jacobian assembly. - */ - void setMatrixReuseable(const bool yesno = true) - { - if (enableJacobianRecycling_()) - reuseMatrix_ = yesno; - } - - /*! - * \brief If partial Jacobian matrix reassembly is enabled, this - * method causes all elements to be reassembled in the next - * assemble() call. - */ - void reassembleAll() - { - // do not reuse the current linearization - reuseMatrix_ = false; - - // do not use partial reassembly for the next iteration - nextReassembleAccuracy_ = 0.0; - if (enablePartialReassemble_()) { - std::fill(vertexColor_.begin(), - vertexColor_.end(), - Red); - std::fill(elementColor_.begin(), - elementColor_.end(), - Red); - std::fill(vertexDelta_.begin(), - vertexDelta_.end(), - 0.0); - } - } - - /*! - * \brief Returns the largest relative error of a "green" vertex - * for the most recent call of the assemble() method. - * - * This only has an effect if partial Jacobian reassembly is - * enabled. If it is disabled, then this method always returns 0. - * - * This returns the _actual_ relative computed seen by - * computeColors(), not the tolerance which it was given. - */ - Scalar reassembleAccuracy() const - { return reassembleAccuracy_; } - - /*! - * \brief Update the distance where the non-linear system was - * originally insistently linearized and the point where it - * will be linerized the next time. - * - * This only has an effect if partial reassemble is enabled. - */ - void updateDiscrepancy(const SolutionVector &u, - const SolutionVector &uDelta) - { - if (!enablePartialReassemble_()) - return; - - // update the vector with the distances of the current - // evaluation point used for linearization from the original - // evaluation point - for (unsigned int i = 0; i < vertexDelta_.size(); ++i) { - PrimaryVariables currentPriVars(u[i]); - PrimaryVariables nextPriVars(currentPriVars); - nextPriVars -= uDelta[i]; - - // we need to add the distance the solution was moved for - // this vertex - Scalar dist = model_().relativeErrorVertex(i, - currentPriVars, - nextPriVars); - vertexDelta_[i] += std::abs(dist); - } - - } - - /*! - * \brief Force to reassemble a given vertex next time the - * assemble() method is called. - * - * \param globalVertIdx The global index of the vertex which ought - * to be red. - */ - void markVertexRed(const int globalVertIdx) - { - if (!enablePartialReassemble_()) - return; - - vertexColor_[globalVertIdx] = Red; - } - /*! * \brief Determine the colors of vertices and elements for partial * reassembly given a relative tolerance. @@ -334,25 +74,25 @@ public: * linearization point and the current solution and * _not_ the delta vector of the Newton iteration! */ - void computeColors(const Scalar relTol) + void computeColors_(const Scalar relTol) { - if (!enablePartialReassemble_()) + if (!this->enablePartialReassemble_()) return; - ElementIterator elemIt = gridView_().template begin<0>(); - ElementIterator elemEndIt = gridView_().template end<0>(); + ElementIterator elemIt = this->gridView_().template begin<0>(); + ElementIterator elemEndIt = this->gridView_().template end<0>(); // mark the red vertices and update the tolerance of the // linearization which actually will get achieved - nextReassembleAccuracy_ = 0; - for (unsigned int i = 0; i < vertexColor_.size(); ++i) { - if (vertexDelta_[i] > relTol) + this->nextReassembleAccuracy_ = 0; + for (unsigned int i = 0; i < this->vertexColor_.size(); ++i) { + if (this->delta_[i] > relTol) // mark vertex as red if discrepancy is larger than // the relative tolerance - vertexColor_[i] = Red; + this->vertexColor_[i] = ParentType::Red; else - nextReassembleAccuracy_ = - std::max(nextReassembleAccuracy_, vertexDelta_[i]); + this->nextReassembleAccuracy_ = + std::max(this->nextReassembleAccuracy_, this->delta_[i]); } // Mark all red elements @@ -362,8 +102,8 @@ public: bool isRed = false; int numVerts = elemIt->template count<dim>(); for (int i=0; i < numVerts; ++i) { - int globalI = vertexMapper_().map(*elemIt, i, dim); - if (vertexColor_[globalI] == Red) { + int globalI = this->vertexMapper_().map(*elemIt, i, dim); + if (this->vertexColor_[globalI] == ParentType::Red) { isRed = true; break; } @@ -371,28 +111,28 @@ public: // if yes, the element color is also red, else it is not // red, i.e. green for the mean time - int globalElemIdx = elementMapper_().map(*elemIt); + int globalElemIdx = this->elementMapper_().map(*elemIt); if (isRed) - elementColor_[globalElemIdx] = Red; + this->elementColor_[globalElemIdx] = ParentType::Red; else - elementColor_[globalElemIdx] = Green; + this->elementColor_[globalElemIdx] = ParentType::Green; } // Mark yellow vertices (as orange for the mean time) - elemIt = gridView_().template begin<0>(); + elemIt = this->gridView_().template begin<0>(); for (; elemIt != elemEndIt; ++elemIt) { int elemIdx = this->elementMapper_().map(*elemIt); - if (elementColor_[elemIdx] != Red) + if (this->elementColor_[elemIdx] != ParentType::Red) continue; // non-red elements do not tint vertices // yellow! int numVerts = elemIt->template count<dim>(); - for (int i=0; i < numVerts; ++i) { - int globalI = vertexMapper_().map(*elemIt, i, dim); + for (int i = 0; i < numVerts; ++i) { + int globalI = this->vertexMapper_().map(*elemIt, i, dim); // if a vertex is already red, don't recolor it to // yellow! - if (vertexColor_[globalI] != Red) { - vertexColor_[globalI] = Orange; + if (this->vertexColor_[globalI] != ParentType::Red) { + this->vertexColor_[globalI] = ParentType::Orange; } } } @@ -400,17 +140,18 @@ public: // at this point we communicate the yellow vertices to the // neighboring processes because a neigbor process may not see // the red vertex for yellow border vertices + typedef typename ParentType::EntityColor EntityColor; VertexHandleMin<EntityColor, std::vector<EntityColor>, VertexMapper> - minHandle(vertexColor_, vertexMapper_()); - gridView_().communicate(minHandle, + minHandle(this->vertexColor_, this->vertexMapper_()); + this->gridView_().communicate(minHandle, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication); // Mark yellow elements - elemIt = gridView_().template begin<0>(); + elemIt = this->gridView_().template begin<0>(); for (; elemIt != elemEndIt; ++elemIt) { int elemIdx = this->elementMapper_().map(*elemIt); - if (elementColor_[elemIdx] == Red) { + if (this->elementColor_[elemIdx] == ParentType::Red) { continue; // element is red already! } @@ -418,149 +159,74 @@ public: // (resp. orange at this point) vertex bool isYellow = false; int numVerts = elemIt->template count<dim>(); - for (int i=0; i < numVerts; ++i) { - int globalI = vertexMapper_().map(*elemIt, i, dim); - if (vertexColor_[globalI] == Orange) { + for (int i = 0; i < numVerts; ++i) { + int globalI = this->vertexMapper_().map(*elemIt, i, dim); + if (this->vertexColor_[globalI] == ParentType::Orange) { isYellow = true; break; } } if (isYellow) - elementColor_[elemIdx] = Yellow; + this->elementColor_[elemIdx] = ParentType::Yellow; } // Demote orange vertices to yellow ones if it has at least // one green element as a neighbor. - elemIt = gridView_().template begin<0>(); + elemIt = this->gridView_().template begin<0>(); for (; elemIt != elemEndIt; ++elemIt) { int elemIdx = this->elementMapper_().map(*elemIt); - if (elementColor_[elemIdx] != Green) + if (this->elementColor_[elemIdx] != ParentType::Green) continue; // yellow and red elements do not make // orange vertices yellow! int numVerts = elemIt->template count<dim>(); - for (int i=0; i < numVerts; ++i) { - int globalI = vertexMapper_().map(*elemIt, i, dim); + for (int i = 0; i < numVerts; ++i) { + int globalI = this->vertexMapper_().map(*elemIt, i, dim); // if a vertex is orange, recolor it to yellow! - if (vertexColor_[globalI] == Orange) - vertexColor_[globalI] = Yellow; + if (this->vertexColor_[globalI] == ParentType::Orange) + this->vertexColor_[globalI] = ParentType::Yellow; } } // demote the border orange vertices VertexHandleMax<EntityColor, std::vector<EntityColor>, VertexMapper> - maxHandle(vertexColor_, - vertexMapper_()); - gridView_().communicate(maxHandle, + maxHandle(this->vertexColor_, + this->vertexMapper_()); + this->gridView_().communicate(maxHandle, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication); // promote the remaining orange vertices to red - for (unsigned int i=0; i < vertexColor_.size(); ++i) { + for (unsigned int i=0; i < this->vertexColor_.size(); ++i) { // if a vertex is green or yellow don't do anything! - if (vertexColor_[i] == Green || vertexColor_[i] == Yellow) + if (this->vertexColor_[i] == ParentType::Green || this->vertexColor_[i] == ParentType::Yellow) continue; // make sure the vertex is red (this is a no-op vertices // which are already red!) - vertexColor_[i] = Red; + this->vertexColor_[i] = ParentType::Red; // set the error of this vertex to 0 because the system // will be consistently linearized at this vertex - vertexDelta_[i] = 0.0; + this->delta_[i] = 0.0; } } - /*! - * \brief Returns the reassemble color of a vertex - * - * \param element An element which contains the vertex - * \param vertIdx The local index of the vertex in the element. - */ - int vertexColor(const Element &element, const int vertIdx) const - { - if (!enablePartialReassemble_()) - return Red; // reassemble unconditionally! - - int globalIdx = vertexMapper_().map(element, vertIdx, dim); - return vertexColor_[globalIdx]; - } - - /*! - * \brief Returns the reassemble color of a vertex - * - * \param globalVertIdx The global index of the vertex. - */ - int vertexColor(const int globalVertIdx) const - { - if (!enablePartialReassemble_()) - return Red; // reassemble unconditionally! - return vertexColor_[globalVertIdx]; - } - - /*! - * \brief Returns the Jacobian reassemble color of an element - * - * \param element The Codim-0 DUNE entity - */ - int elementColor(const Element &element) const - { - if (!enablePartialReassemble_()) - return Red; // reassemble unconditionally! - - int globalIdx = elementMapper_().map(element); - return elementColor_[globalIdx]; - } - - /*! - * \brief Returns the Jacobian reassemble color of an element - * - * \param globalElementIdx The global index of the element. - */ - int elementColor(const int globalElementIdx) const - { - if (!enablePartialReassemble_()) - return Red; // reassemble unconditionally! - return elementColor_[globalElementIdx]; - } - - /*! - * \brief Return constant reference to global Jacobian matrix. - */ - const JacobianMatrix& matrix() const - { return *matrix_; } - JacobianMatrix& matrix() - { return *matrix_; } - - /*! - * \brief Return constant reference to global residual vector. - */ - const SolutionVector& residual() const - { return residual_; } - SolutionVector& residual() - { return residual_; } - -private: - static bool enableJacobianRecycling_() - { return GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnableJacobianRecycling); } - static bool enablePartialReassemble_() - { return GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnablePartialReassemble); } - // Construct the BCRS matrix for the global jacobian void createMatrix_() { - int numVerticesGlobal = gridView_().size(dim); + int numVerticesGlobal = this->gridView_().size(dim); // allocate raw matrix - matrix_ = new JacobianMatrix(numVerticesGlobal, numVerticesGlobal, JacobianMatrix::random); + this->matrix_ = new JacobianMatrix(numVerticesGlobal, numVerticesGlobal, JacobianMatrix::random); // find out the global indices of the neighboring vertices of // each vertex typedef std::set<int> NeighborSet; std::vector<NeighborSet> neighbors(numVerticesGlobal); - ElementIterator eIt = gridView_().template begin<0>(); - const ElementIterator eEndIt = gridView_().template end<0>(); + ElementIterator eIt = this->gridView_().template begin<0>(); + const ElementIterator eEndIt = this->gridView_().template end<0>(); for (; eIt != eEndIt; ++eIt) { const Element &elem = *eIt; int numVerticesLocal = elem.template count<dim>(); @@ -571,7 +237,7 @@ private: elem.partitionType() != Dune::BorderEntity) { for (int i = 0; i < numVerticesLocal; ++i) { - int globalI = vertexMapper_().map(*eIt, i, dim); + int globalI = this->vertexMapper_().map(*eIt, i, dim); neighbors[globalI].insert(globalI); } } @@ -579,9 +245,9 @@ private: { // loop over all element vertices for (int i = 0; i < numVerticesLocal - 1; ++i) { - int globalI = vertexMapper_().map(*eIt, i, dim); + int globalI = this->vertexMapper_().map(*eIt, i, dim); for (int j = i + 1; j < numVerticesLocal; ++j) { - int globalJ = vertexMapper_().map(*eIt, j, dim); + int globalJ = this->vertexMapper_().map(*eIt, j, dim); // make sure that vertex j is in the neighbor set // of vertex i and vice-versa neighbors[globalI].insert(globalJ); @@ -598,9 +264,9 @@ private: // allocate space for the rows of the matrix for (int i = 0; i < numVerticesGlobal; ++i) { - matrix_->setrowsize(i, neighbors[i].size()); + this->matrix_->setrowsize(i, neighbors[i].size()); } - matrix_->endrowsizes(); + this->matrix_->endrowsizes(); // fill the rows with indices. each vertex talks to all of its // neighbors. (it also talks to itself since vertices are @@ -609,158 +275,51 @@ private: typename NeighborSet::iterator nIt = neighbors[i].begin(); typename NeighborSet::iterator nEndIt = neighbors[i].end(); for (; nIt != nEndIt; ++nIt) { - matrix_->addindex(i, *nIt); - } - } - matrix_->endindices(); - } - - // reset the global linear system of equations. if partial - // reassemble is enabled, this means that the jacobian matrix must - // only be erased partially! - void resetSystem_() - { - // do not do anything if we can re-use the current linearization - if (reuseMatrix_) - return; - - // reset the right hand side. - residual_ = 0.0; - - if (!enablePartialReassemble_()) { - // If partial reassembly of the jacobian is not enabled, - // we can just reset everything! - (*matrix_) = 0; - - // reset the parts needed for Jacobian recycling - if (enableJacobianRecycling_()) { - int numVerticesGlobal = matrix_->N(); - for (int i=0; i < numVerticesGlobal; ++ i) { - storageJacobian_[i] = 0; - storageTerm_[i] = 0; - } - } - - return; - } - - // reset all entries corrosponding to a red or yellow vertex - for (unsigned int rowIdx = 0; rowIdx < matrix_->N(); ++rowIdx) { - if (vertexColor_[rowIdx] == Green) - continue; // the equations for this control volume are - // already below the treshold - - // here we have yellow or red vertices... - - // reset the parts needed for Jacobian recycling - if (enableJacobianRecycling_()) { - storageJacobian_[rowIdx] = 0; - storageTerm_[rowIdx] = 0; - } - - // set all matrix entries in the row to 0 - typedef typename JacobianMatrix::ColIterator ColIterator; - ColIterator colIt = (*matrix_)[rowIdx].begin(); - const ColIterator &colEndIt = (*matrix_)[rowIdx].end(); - for (; colIt != colEndIt; ++colIt) { - (*colIt) = 0.0; - } - } - } - - // linearize the whole system - void assemble_() - { - resetSystem_(); - - // if we can "recycle" the current linearization, we do it - // here and be done with it... - Scalar curDt = problem_().timeManager().timeStepSize(); - if (reuseMatrix_) { - int numVerticesGlobal = storageJacobian_.size(); - for (int i = 0; i < numVerticesGlobal; ++i) { - // rescale the mass term of the jacobian matrix - MatrixBlock &J_i_i = (*matrix_)[i][i]; - - J_i_i -= storageJacobian_[i]; - storageJacobian_[i] *= oldDt_/curDt; - J_i_i += storageJacobian_[i]; - - // use the flux term plus the source term as the new - // residual (since the delta in the d(storage)/dt is 0 - // for the first iteration and the residual is - // approximately 0 in the last iteration, the flux - // term plus the source term must be equal to the - // negative change of the storage term of the last - // iteration of the last time step...) - residual_[i] = storageTerm_[i]; - residual_[i] *= -1; - } - - reuseMatrix_ = false; - oldDt_ = curDt; - return; - } - - oldDt_ = curDt; - greenElems_ = 0; - - // reassemble the elements... - ElementIterator elemIt = gridView_().template begin<0>(); - ElementIterator elemEndIt = gridView_().template end<0>(); - for (; elemIt != elemEndIt; ++elemIt) { - const Element &elem = *elemIt; - if (elem.partitionType() != Dune::InteriorEntity && - elem.partitionType() != Dune::BorderEntity) - { - assembleGhostElement_(elem); - } - else - { - assembleElement_(elem); + this->matrix_->addindex(i, *nIt); } } + this->matrix_->endindices(); } // assemble a non-ghost element void assembleElement_(const Element &elem) { - if (enablePartialReassemble_()) { - int globalElemIdx = model_().elementMapper().map(elem); - if (elementColor_[globalElemIdx] == Green) { - ++greenElems_; + if (this->enablePartialReassemble_()) { + int globalElemIdx = this->model_().elementMapper().map(elem); + if (this->elementColor_[globalElemIdx] == ParentType::Green) { + ++this->greenElems_; assembleGreenElement_(elem); return; } } - model_().localJacobian().assemble(elem); + this->model_().localJacobian().assemble(elem); int numVerticesLocal = elem.template count<dim>(); for (int i=0; i < numVerticesLocal; ++ i) { - int globI = vertexMapper_().map(elem, i, dim); + int globI = this->vertexMapper_().map(elem, i, dim); // update the right hand side - residual_[globI] += model_().localJacobian().residual(i); - for (int j = 0; j < residual_[globI].dimension; ++j) - assert(std::isfinite(residual_[globI][j])); - if (enableJacobianRecycling_()) { - storageTerm_[globI] += - model_().localJacobian().storageTerm(i); + this->residual_[globI] += this->model_().localJacobian().residual(i); + for (int j = 0; j < this->residual_[globI].dimension; ++j) + assert(std::isfinite(this->residual_[globI][j])); + if (this->enableJacobianRecycling_()) { + this->storageTerm_[globI] += + this->model_().localJacobian().storageTerm(i); } // only update the jacobian matrix for non-green vertices - if (vertexColor(globI) != Green) { - if (enableJacobianRecycling_()) - storageJacobian_[globI] += - model_().localJacobian().storageJacobian(i); + if (this->vertexColor(globI) != ParentType::Green) { + if (this->enableJacobianRecycling_()) + this->storageJacobian_[globI] += + this->model_().localJacobian().storageJacobian(i); // update the jacobian matrix - for (int j=0; j < numVerticesLocal; ++ j) { - int globJ = vertexMapper_().map(elem, j, dim); - (*matrix_)[globI][globJ] += - model_().localJacobian().mat(i,j); + for (int j = 0; j < numVerticesLocal; ++ j) { + int globJ = this->vertexMapper_().map(elem, j, dim); + (*this->matrix_)[globI][globJ] += + this->model_().localJacobian().mat(i,j); } } } @@ -770,16 +329,16 @@ private: // residual updated, but the jacobian is left alone... void assembleGreenElement_(const Element &elem) { - model_().localResidual().eval(elem); + this->model_().localResidual().eval(elem); int numVerticesLocal = elem.template count<dim>(); - for (int i=0; i < numVerticesLocal; ++ i) { - int globI = vertexMapper_().map(elem, i, dim); + for (int i = 0; i < numVerticesLocal; ++ i) { + int globI = this->vertexMapper_().map(elem, i, dim); // update the right hand side - residual_[globI] += model_().localResidual().residual(i); - if (enableJacobianRecycling_()) - storageTerm_[globI] += model_().localResidual().storageTerm(i); + this->residual_[globI] += this->model_().localResidual().residual(i); + if (this->enableJacobianRecycling_()) + this->storageTerm_[globI] += this->model_().localResidual().storageTerm(i); } } @@ -798,59 +357,16 @@ private: } // set main diagonal entries for the vertex - int vIdx = vertexMapper_().map(*vp); + int vIdx = this->vertexMapper_().map(*vp); typedef typename JacobianMatrix::block_type BlockType; - BlockType &J = (*matrix_)[vIdx][vIdx]; + BlockType &J = (*this->matrix_)[vIdx][vIdx]; for (int j = 0; j < BlockType::rows; ++j) J[j][j] = 1.0; // set residual for the vertex - residual_[vIdx] = 0; + this->residual_[vIdx] = 0; } } - - - Problem &problem_() - { return *problemPtr_; } - const Problem &problem_() const - { return *problemPtr_; } - const Model &model_() const - { return problem_().model(); } - Model &model_() - { return problem_().model(); } - const GridView &gridView_() const - { return problem_().gridView(); } - const VertexMapper &vertexMapper_() const - { return problem_().vertexMapper(); } - const ElementMapper &elementMapper_() const - { return problem_().elementMapper(); } - - Problem *problemPtr_; - - // the jacobian matrix - JacobianMatrix *matrix_; - // the right-hand side - SolutionVector residual_; - - // attributes required for jacobian matrix recycling - bool reuseMatrix_; - // The storage part of the local Jacobian - std::vector<MatrixBlock> storageJacobian_; - std::vector<VectorBlock> storageTerm_; - // time step size of last assembly - Scalar oldDt_; - - - // attributes required for partial jacobian reassembly - std::vector<EntityColor> vertexColor_; - std::vector<EntityColor> elementColor_; - std::vector<Scalar> vertexDelta_; - - int totalElems_; - int greenElems_; - - Scalar nextReassembleAccuracy_; - Scalar reassembleAccuracy_; }; } // namespace Dumux diff --git a/dumux/implicit/cellcentered/ccassembler.hh b/dumux/implicit/cellcentered/ccassembler.hh index 8969c898fb..f4285df634 100644 --- a/dumux/implicit/cellcentered/ccassembler.hh +++ b/dumux/implicit/cellcentered/ccassembler.hh @@ -23,261 +23,39 @@ /*! * \file * - * \brief An assembler for the global Jacobian matrix for models using the box discretization. + * \brief An assembler for the global Jacobian matrix for models using the cell centered discretization. */ #ifndef DUMUX_CC_ASSEMBLER_HH #define DUMUX_CC_ASSEMBLER_HH -#include <dune/grid/common/gridenums.hh> - -#include <dumux/implicit/cellcentered/ccproperties.hh> -#include <dumux/linear/vertexborderlistfromgrid.hh> -#include <dumux/linear/foreignoverlapfrombcrsmatrix.hh> -#include <dumux/parallel/vertexhandles.hh> +#include <dumux/implicit/common/implicitassembler.hh> namespace Dumux { /*! - * \brief An assembler for the global Jacobian matrix for models using the box discretization. + * \brief An assembler for the global Jacobian matrix for models using the cell centered discretization. */ template<class TypeTag> -class CCAssembler +class CCAssembler : public ImplicitAssembler<TypeTag> { - typedef typename GET_PROP_TYPE(TypeTag, Model) Model; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef ImplicitAssembler<TypeTag> ParentType; + friend class ImplicitAssembler<TypeTag>; typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; - typedef typename GET_PROP_TYPE(TypeTag, ElementMapper) ElementMapper; - - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - - enum{ dim = GridView::dimension }; typedef typename GridView::template Codim<0>::Entity Element; typedef typename GridView::template Codim<0>::Iterator ElementIterator; - typedef typename GridView::template Codim<dim>::EntityPointer VertexPointer; + enum{ dim = GridView::dimension }; typedef typename GridView::IntersectionIterator IntersectionIterator; - enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; - typedef Dune::FieldMatrix<Scalar, numEq, numEq> MatrixBlock; - typedef Dune::FieldVector<Scalar, numEq> VectorBlock; +public: + CCAssembler(): ParentType() {} +private: // copying the jacobian assembler is not a good idea CCAssembler(const CCAssembler &); -public: - /*! - * \brief The colors of elements required for partial - * Jacobian reassembly. - */ - enum EntityColor { - /*! - * Element that needs to be reassembled because some - * relative error is above the tolerance - */ - Red = 0, - - /*! - * Element that does not need to be reassembled - */ - Green = 3 - }; - - CCAssembler() - { - problemPtr_ = 0; - matrix_ = 0; - - // set reassemble accuracy to 0, so that if partial reassembly - // of the jacobian matrix is disabled, the reassemble accuracy - // is always smaller than the current relative tolerance - reassembleAccuracy_ = 0.0; - } - - ~CCAssembler() - { - delete matrix_; - } - - /*! - * \brief Initialize the jacobian assembler. - * - * At this point we can assume that all objects in the problem and - * the model have been allocated. We can not assume that they are - * fully initialized, though. - * - * \param problem The problem object - */ - void init(Problem& problem) - { - problemPtr_ = &problem; - - // initialize the BCRS matrix - createMatrix_(); - - // initialize the jacobian matrix and the right hand side - // vector - *matrix_ = 0; - reuseMatrix_ = false; - - int numElems = gridView_().size(0); - - residual_.resize(numElems); - - // initialize the storage part of the Jacobian matrix. Since - // we only need this if Jacobian matrix recycling is enabled, - // we do not waste space if it is disabled - if (enableJacobianRecycling_()) { - storageJacobian_.resize(numElems); - storageTerm_.resize(numElems); - } - - if (gridView_().comm().size() > 1) - totalElems_ = gridView_().comm().sum(numElems); - else - totalElems_ = numElems; - - // initialize data needed for partial reassembly - if (enablePartialReassemble_()) - { - elementColor_.resize(numElems); - elementDelta_.resize(numElems); - } - - reassembleAll(); - } - - /*! - * \brief Assemble the global Jacobian of the residual and the residual for the current solution. - * - * The current state of affairs (esp. the previous and the current - * solutions) is represented by the model object. - */ - void assemble() - { - bool printReassembleStatistics = enablePartialReassemble_() && !reuseMatrix_; - int succeeded; - try { - assemble_(); - succeeded = 1; - if (gridView_().comm().size() > 1) - succeeded = gridView_().comm().min(succeeded); - } - catch (Dumux::NumericalProblem &e) - { - std::cout << "rank " << problem_().gridView().comm().rank() - << " caught an exception while assembling:" << e.what() - << "\n"; - succeeded = 0; - if (gridView_().comm().size() > 1) - succeeded = gridView_().comm().min(succeeded); - } - - if (!succeeded) { - DUNE_THROW(NumericalProblem, - "A process did not succeed in linearizing the system"); - } - - if (printReassembleStatistics) - { - if (gridView_().comm().size() > 1) - { - greenElems_ = gridView_().comm().sum(greenElems_); - reassembleAccuracy_ = gridView_().comm().max(nextReassembleAccuracy_); - } - else - { - reassembleAccuracy_ = nextReassembleAccuracy_; - } - - problem_().newtonController().endIterMsg() - << ", reassembled " - << totalElems_ - greenElems_ << "/" << totalElems_ - << " (" << 100*Scalar(totalElems_ - greenElems_)/totalElems_ << "%) elems @accuracy=" - << reassembleAccuracy_; - } - } - - /*! - * \brief If Jacobian matrix recycling is enabled, this method - * specifies whether the next call to assemble() just - * rescales the storage term or does a full reassembly - * - * \param yesno If true, only rescale; else do full Jacobian assembly. - */ - void setMatrixReuseable(bool yesno = true) - { - if (enableJacobianRecycling_()) - reuseMatrix_ = yesno; - } - - /*! - * \brief If partial Jacobian matrix reassembly is enabled, this - * method causes all elements to be reassembled in the next - * assemble() call. - */ - void reassembleAll() - { - // do not reuse the current linearization - reuseMatrix_ = false; - - // do not use partial reassembly for the next iteration - nextReassembleAccuracy_ = 0.0; - if (enablePartialReassemble_()) { - std::fill(elementColor_.begin(), - elementColor_.end(), - Red); - std::fill(elementDelta_.begin(), - elementDelta_.end(), - 0.0); - } - } - - /*! - * \brief Returns the largest relative error of a "green" vertex - * for the most recent call of the assemble() method. - * - * This only has an effect if partial Jacobian reassembly is - * enabled. If it is disabled, then this method always returns 0. - * - * This returns the _actual_ relative computed seen by - * computeColors(), not the tolerance which it was given. - */ - Scalar reassembleAccuracy() const - { return reassembleAccuracy_; } - - /*! - * \brief Update the distance where the non-linear system was - * originally insistently linearized and the point where it - * will be linerized the next time. - * - * This only has an effect if partial reassemble is enabled. - */ - void updateDiscrepancy(const SolutionVector &u, - const SolutionVector &uDelta) - { - if (!enablePartialReassemble_()) - return; - - // update the vector with the distances of the current - // evaluation point used for linearization from the original - // evaluation point - for (unsigned int i = 0; i < elementDelta_.size(); ++i) { - PrimaryVariables currentPriVars(u[i]); - PrimaryVariables nextPriVars(currentPriVars); - nextPriVars -= uDelta[i]; - - // we need to add the distance the solution was moved for - // this vertex - Scalar dist = model_().relativeErrorVertex(i, - currentPriVars, - nextPriVars); - elementDelta_[i] += std::abs(dist); - } - } - /*! * \brief Determine the colors of elements for partial * reassembly given a relative tolerance. @@ -295,130 +73,79 @@ public: * linearization point and the current solution and * _not_ the delta vector of the Newton iteration! */ - void computeColors(Scalar relTol) + void computeColors_(Scalar relTol) { - if (!enablePartialReassemble_()) + if (!this->enablePartialReassemble_()) return; - ElementIterator elemIt = gridView_().template begin<0>(); - ElementIterator elemEndIt = gridView_().template end<0>(); + ElementIterator elemIt = this->gridView_().template begin<0>(); + ElementIterator elemEndIt = this->gridView_().template end<0>(); // mark the red elements and update the tolerance of the // linearization which actually will get achieved - nextReassembleAccuracy_ = 0; + this->nextReassembleAccuracy_ = 0; for (; elemIt != elemEndIt; ++elemIt) { int elemIdx = this->elementMapper_().map(*elemIt); - if (elementDelta_[elemIdx] > relTol) + if (this->delta_[elemIdx] > relTol) { // mark element as red if discrepancy is larger than // the relative tolerance - elementColor_[elemIdx] = Red; + this->elementColor_[elemIdx] = ParentType::Red; } else { - elementColor_[elemIdx] = Green; - nextReassembleAccuracy_ = - std::max(nextReassembleAccuracy_, elementDelta_[elemIdx]); + this->elementColor_[elemIdx] = ParentType::Green; + this->nextReassembleAccuracy_ = + std::max(this->nextReassembleAccuracy_, this->delta_[elemIdx]); } } // mark the neighbors also red - elemIt = gridView_().template begin<0>(); + elemIt = this->gridView_().template begin<0>(); for (; elemIt != elemEndIt; ++elemIt) { int elemIdx = this->elementMapper_().map(*elemIt); - if (elementColor_[elemIdx] == Red) + if (this->elementColor_[elemIdx] == ParentType::Red) continue; // element is red already! - if (elementDelta_[elemIdx] > relTol) + if (this->delta_[elemIdx] > relTol) { // also mark the neighbors - IntersectionIterator endIsIt = gridView_().iend(*elemIt); - for (IntersectionIterator isIt = gridView_().ibegin(*elemIt); isIt != endIsIt; ++isIt) + IntersectionIterator endIsIt = this->gridView_().iend(*elemIt); + for (IntersectionIterator isIt = this->gridView_().ibegin(*elemIt); isIt != endIsIt; ++isIt) { if (isIt->neighbor()) { int neighborIdx = this->elementMapper_().map(*isIt->outside()); - elementColor_[neighborIdx] = Red; + this->elementColor_[neighborIdx] = ParentType::Red; } } } } // set the discrepancy of the red elements to zero - for (int i = 0; i < elementDelta_.size(); i++) - if (elementColor_[i] == Red) - elementDelta_[i] = 0; - } - - /*! - * \brief Returns the Jacobian reassemble color of an element - * - * \param element The Codim-0 DUNE entity - */ - int elementColor(const Element &element) const - { - if (!enablePartialReassemble_()) - return Red; // reassemble unconditionally! - - int globalIdx = elementMapper_().map(element); - return elementColor_[globalIdx]; - } - - /*! - * \brief Returns the Jacobian reassemble color of an element - * - * \param globalElementIdx The global index of the element. - */ - int elementColor(const int globalElementIdx) const - { - if (!enablePartialReassemble_()) - return Red; // reassemble unconditionally! - return elementColor_[globalElementIdx]; + for (int i = 0; i < this->delta_.size(); i++) + if (this->elementColor_[i] == ParentType::Red) + this->delta_[i] = 0; } - - /*! - * \brief Return constant reference to global Jacobian matrix. - */ - const JacobianMatrix& matrix() const - { return *matrix_; } - JacobianMatrix& matrix() - { return *matrix_; } - - /*! - * \brief Return constant reference to global residual vector. - */ - const SolutionVector& residual() const - { return residual_; } - SolutionVector& residual() - { return residual_; } - // functions needed for interface consistence - void markVertexRed(const int globalVertIdx) {} - -private: - static bool enableJacobianRecycling_() - { return GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnableJacobianRecycling); } - static bool enablePartialReassemble_() - { return GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnablePartialReassemble); } - // Construct the BCRS matrix for the global jacobian void createMatrix_() { - int nElems = gridView_().size(0); + int nElems = this->gridView_().size(0); // allocate raw matrix - matrix_ = new JacobianMatrix(nElems, nElems, JacobianMatrix::random); + this->matrix_ = new JacobianMatrix(nElems, nElems, JacobianMatrix::random); // find out the global indices of the neighboring elements of // each element typedef std::set<int> NeighborSet; std::vector<NeighborSet> neighbors(nElems); - ElementIterator eIt = gridView_().template begin<0>(); - const ElementIterator eEndIt = gridView_().template end<0>(); + ElementIterator eIt = this->gridView_().template begin<0>(); + const ElementIterator eEndIt = this->gridView_().template end<0>(); for (; eIt != eEndIt; ++eIt) { const Element &elem = *eIt; - int globalI = elementMapper_().map(elem); + int globalI = this->elementMapper_().map(elem); neighbors[globalI].insert(globalI); // if the element is ghost, @@ -427,13 +154,13 @@ private: // continue; // loop over all neighbors - IntersectionIterator isIt = gridView_().ibegin(elem); - const IntersectionIterator &endIt = gridView_().iend(elem); + IntersectionIterator isIt = this->gridView_().ibegin(elem); + const IntersectionIterator &endIt = this->gridView_().iend(elem); for (; isIt != endIt; ++isIt) { if (isIt->neighbor()) { - int globalJ = elementMapper_().map(*(isIt->outside())); + int globalJ = this->elementMapper_().map(*(isIt->outside())); neighbors[globalI].insert(globalJ); } } @@ -441,9 +168,9 @@ private: // allocate space for the rows of the matrix for (int i = 0; i < nElems; ++i) { - matrix_->setrowsize(i, neighbors[i].size()); + this->matrix_->setrowsize(i, neighbors[i].size()); } - matrix_->endrowsizes(); + this->matrix_->endrowsizes(); // fill the rows with indices. each element talks to all of its // neighbors and itself. @@ -451,157 +178,53 @@ private: typename NeighborSet::iterator nIt = neighbors[i].begin(); typename NeighborSet::iterator nEndIt = neighbors[i].end(); for (; nIt != nEndIt; ++nIt) { - matrix_->addindex(i, *nIt); + this->matrix_->addindex(i, *nIt); } } - matrix_->endindices(); + this->matrix_->endindices(); } - // reset the global linear system of equations. if partial - // reassemble is enabled, this means that the jacobian matrix must - // only be erased partially! - void resetSystem_() - { - // do not do anything if we can re-use the current linearization - if (reuseMatrix_) - return; - - // reset the right hand side. - residual_ = 0.0; - - if (!enablePartialReassemble_()) { - // If partial reassembly of the jacobian is not enabled, - // we can just reset everything! - (*matrix_) = 0; - - // reset the parts needed for Jacobian recycling - if (enableJacobianRecycling_()) { - int numElementsGlobal = matrix_->N(); - for (int i=0; i < numElementsGlobal; ++ i) { - storageJacobian_[i] = 0; - storageTerm_[i] = 0; - } - } - - return; - } - - // reset all entries corrosponding to a red or yellow vertex - for (unsigned int rowIdx = 0; rowIdx < matrix_->N(); ++rowIdx) { - if (elementColor_[rowIdx] == Green) - continue; // the equations for this control volume are - // already below the treshold - - // reset the parts needed for Jacobian recycling - if (enableJacobianRecycling_()) { - storageJacobian_[rowIdx] = 0; - storageTerm_[rowIdx] = 0; - } - - // set all matrix entries in the row to 0 - typedef typename JacobianMatrix::ColIterator ColIterator; - ColIterator colIt = (*matrix_)[rowIdx].begin(); - const ColIterator &colEndIt = (*matrix_)[rowIdx].end(); - for (; colIt != colEndIt; ++colIt) { - (*colIt) = 0.0; - } - } - } - - // linearize the whole system - void assemble_() - { - resetSystem_(); - - // if we can "recycle" the current linearization, we do it - // here and be done with it... - Scalar curDt = problem_().timeManager().timeStepSize(); - if (reuseMatrix_) { - int numElementsGlobal = storageJacobian_.size(); - for (int i = 0; i < numElementsGlobal; ++i) { - // rescale the mass term of the jacobian matrix - MatrixBlock &J_i_i = (*matrix_)[i][i]; - - J_i_i -= storageJacobian_[i]; - storageJacobian_[i] *= oldDt_/curDt; - J_i_i += storageJacobian_[i]; - - // use the flux term plus the source term as the new - // residual (since the delta in the d(storage)/dt is 0 - // for the first iteration and the residual is - // approximately 0 in the last iteration, the flux - // term plus the source term must be equal to the - // negative change of the storage term of the last - // iteration of the last time step...) - residual_[i] = storageTerm_[i]; - residual_[i] *= -1; - } - - reuseMatrix_ = false; - oldDt_ = curDt; - return; - } - - oldDt_ = curDt; - greenElems_ = 0; - - // reassemble the elements... - ElementIterator elemIt = gridView_().template begin<0>(); - ElementIterator elemEndIt = gridView_().template end<0>(); - for (; elemIt != elemEndIt; ++elemIt) { - const Element &elem = *elemIt; - if (elem.partitionType() == Dune::GhostEntity) - { - assembleGhostElement_(elem); - } - else - { - assembleElement_(elem); - } - } - } - // assemble a non-ghost element void assembleElement_(const Element &elem) { - if (enablePartialReassemble_()) { - int globalElemIdx = model_().elementMapper().map(elem); - if (elementColor_[globalElemIdx] == Green) { - ++greenElems_; + if (this->enablePartialReassemble_()) { + int globalElemIdx = this->model_().elementMapper().map(elem); + if (this->elementColor_[globalElemIdx] == ParentType::Green) { + ++this->greenElems_; assembleGreenElement_(elem); return; } } - model_().localJacobian().assemble(elem); + this->model_().localJacobian().assemble(elem); - int globalI = elementMapper_().map(elem); + int globalI = this->elementMapper_().map(elem); // update the right hand side - residual_[globalI] = model_().localJacobian().residual(0); - for (int j = 0; j < residual_[globalI].dimension; ++j) - assert(std::isfinite(residual_[globalI][j])); - if (enableJacobianRecycling_()) { - storageTerm_[globalI] += - model_().localJacobian().storageTerm(0); + this->residual_[globalI] = this->model_().localJacobian().residual(0); + for (int j = 0; j < this->residual_[globalI].dimension; ++j) + assert(std::isfinite(this->residual_[globalI][j])); + if (this->enableJacobianRecycling_()) { + this->storageTerm_[globalI] += + this->model_().localJacobian().storageTerm(0); } - if (enableJacobianRecycling_()) - storageJacobian_[globalI] += - model_().localJacobian().storageJacobian(0); + if (this->enableJacobianRecycling_()) + this->storageJacobian_[globalI] += + this->model_().localJacobian().storageJacobian(0); // update the diagonal entry - (*matrix_)[globalI][globalI] = model_().localJacobian().mat(0,0); + (*this->matrix_)[globalI][globalI] = this->model_().localJacobian().mat(0,0); - IntersectionIterator isIt = gridView_().ibegin(elem); - const IntersectionIterator &endIt = gridView_().iend(elem); + IntersectionIterator isIt = this->gridView_().ibegin(elem); + const IntersectionIterator &endIt = this->gridView_().iend(elem); for (int j = 0; isIt != endIt; ++isIt) { if (isIt->neighbor()) { - int globalJ = elementMapper_().map(*(isIt->outside())); - (*matrix_)[globalI][globalJ] = model_().localJacobian().mat(0,++j); + int globalJ = this->elementMapper_().map(*(isIt->outside())); + (*this->matrix_)[globalI][globalJ] = this->model_().localJacobian().mat(0,++j); } } } @@ -610,72 +233,30 @@ private: // residual updated, but the jacobian is left alone... void assembleGreenElement_(const Element &elem) { - model_().localResidual().eval(elem); + this->model_().localResidual().eval(elem); - int globalI = elementMapper_().map(elem); + int globalI = this->elementMapper_().map(elem); // update the right hand side - residual_[globalI] += model_().localResidual().residual(0); - if (enableJacobianRecycling_()) - storageTerm_[globalI] += model_().localResidual().storageTerm(0); + this->residual_[globalI] += this->model_().localResidual().residual(0); + if (this->enableJacobianRecycling_()) + this->storageTerm_[globalI] += this->model_().localResidual().storageTerm(0); } // "assemble" a ghost element void assembleGhostElement_(const Element &elem) { - int globalI = elementMapper_().map(elem); + int globalI = this->elementMapper_().map(elem); // update the right hand side - residual_[globalI] = 0.0; + this->residual_[globalI] = 0.0; // update the diagonal entry typedef typename JacobianMatrix::block_type BlockType; - BlockType &J = (*matrix_)[globalI][globalI]; + BlockType &J = (*this->matrix_)[globalI][globalI]; for (int j = 0; j < BlockType::rows; ++j) J[j][j] = 1.0; } - - - Problem &problem_() - { return *problemPtr_; } - const Problem &problem_() const - { return *problemPtr_; } - const Model &model_() const - { return problem_().model(); } - Model &model_() - { return problem_().model(); } - const GridView &gridView_() const - { return problem_().gridView(); } - const VertexMapper &vertexMapper_() const - { return problem_().vertexMapper(); } - const ElementMapper &elementMapper_() const - { return problem_().elementMapper(); } - - Problem *problemPtr_; - - // the jacobian matrix - JacobianMatrix *matrix_; - // the right-hand side - SolutionVector residual_; - - // attributes required for jacobian matrix recycling - bool reuseMatrix_; - // The storage part of the local Jacobian - std::vector<MatrixBlock> storageJacobian_; - std::vector<VectorBlock> storageTerm_; - // time step size of last assembly - Scalar oldDt_; - - - // attributes required for partial jacobian reassembly - std::vector<EntityColor> elementColor_; - std::vector<Scalar> elementDelta_; - - int totalElems_; - int greenElems_; - - Scalar nextReassembleAccuracy_; - Scalar reassembleAccuracy_; }; } // namespace Dumux diff --git a/dumux/implicit/common/implicitassembler.hh b/dumux/implicit/common/implicitassembler.hh index d585d360a2..5ca3d76c91 100644 --- a/dumux/implicit/common/implicitassembler.hh +++ b/dumux/implicit/common/implicitassembler.hh @@ -19,26 +19,22 @@ /*! * \file * - * \brief An assembler for the global Jacobian matrix for models using the box discretization. + * \brief An assembler for the global Jacobian matrix for fully implicit models. */ -#ifndef DUMUX_BOX_ASSEMBLER_HH -#define DUMUX_BOX_ASSEMBLER_HH +#ifndef DUMUX_IMPLICIT_ASSEMBLER_HH +#define DUMUX_IMPLICIT_ASSEMBLER_HH -#include <dune/grid/common/gridenums.hh> - -#include <dumux/implicit/box/boxproperties.hh> -#include <dumux/linear/vertexborderlistfromgrid.hh> -#include <dumux/linear/foreignoverlapfrombcrsmatrix.hh> -#include <dumux/parallel/vertexhandles.hh> +#include "implicitproperties.hh" namespace Dumux { /*! - * \brief An assembler for the global Jacobian matrix for models using the box discretization. + * \brief An assembler for the global Jacobian matrix for fully implicit models. */ template<class TypeTag> -class BoxAssembler +class ImplicitAssembler { + typedef typename GET_PROP_TYPE(TypeTag, JacobianAssembler) Implementation; typedef typename GET_PROP_TYPE(TypeTag, Model) Model; typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; @@ -59,8 +55,10 @@ class BoxAssembler typedef Dune::FieldMatrix<Scalar, numEq, numEq> MatrixBlock; typedef Dune::FieldVector<Scalar, numEq> VectorBlock; + enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; + // copying the jacobian assembler is not a good idea - BoxAssembler(const BoxAssembler &); + ImplicitAssembler(const ImplicitAssembler &); public: /*! @@ -96,7 +94,7 @@ public: Green = 3 }; - BoxAssembler() + ImplicitAssembler() { problemPtr_ = 0; matrix_ = 0; @@ -107,7 +105,7 @@ public: reassembleAccuracy_ = 0.0; } - ~BoxAssembler() + ~ImplicitAssembler() { delete matrix_; } @@ -126,7 +124,7 @@ public: problemPtr_ = &problem; // initialize the BCRS matrix - createMatrix_(); + asImp_().createMatrix_(); // initialize the jacobian matrix and the right hand side // vector @@ -135,15 +133,16 @@ public: int numVerts = gridView_().size(dim); int numElems = gridView_().size(0); + int numDofs = problem.model().numDofs(); - residual_.resize(numVerts); + residual_.resize(numDofs); // initialize the storage part of the Jacobian matrix. Since // we only need this if Jacobian matrix recycling is enabled, // we do not waste space if it is disabled if (enableJacobianRecycling_()) { - storageJacobian_.resize(numVerts); - storageTerm_.resize(numVerts); + storageJacobian_.resize(numDofs); + storageTerm_.resize(numDofs); } if (gridView_().comm().size() > 1) @@ -153,9 +152,10 @@ public: // initialize data needed for partial reassembly if (enablePartialReassemble_()) { - vertexColor_.resize(numVerts); - vertexDelta_.resize(numVerts); + delta_.resize(numDofs); elementColor_.resize(numElems); + if (isBox) + vertexColor_.resize(numVerts); } reassembleAll(); } @@ -248,8 +248,8 @@ public: std::fill(elementColor_.begin(), elementColor_.end(), Red); - std::fill(vertexDelta_.begin(), - vertexDelta_.end(), + std::fill(delta_.begin(), + delta_.end(), 0.0); } } @@ -283,7 +283,7 @@ public: // update the vector with the distances of the current // evaluation point used for linearization from the original // evaluation point - for (unsigned int i = 0; i < vertexDelta_.size(); ++i) { + for (unsigned int i = 0; i < delta_.size(); ++i) { PrimaryVariables currentPriVars(u[i]); PrimaryVariables nextPriVars(currentPriVars); nextPriVars -= uDelta[i]; @@ -293,7 +293,7 @@ public: Scalar dist = model_().relativeErrorVertex(i, currentPriVars, nextPriVars); - vertexDelta_[i] += std::abs(dist); + delta_[i] += std::abs(dist); } } @@ -317,17 +317,6 @@ public: * \brief Determine the colors of vertices and elements for partial * reassembly given a relative tolerance. * - * The following approach is used: - * - * - Set all vertices and elements to 'green' - * - Mark all vertices as 'red' which exhibit an relative error above - * the tolerance - * - Mark all elements which feature a 'red' vetex as 'red' - * - Mark all vertices which are not 'red' and are part of a - * 'red' element as 'yellow' - * - Mark all elements which are not 'red' and contain a - * 'yellow' vertex as 'yellow' - * * \param relTol The relative error below which a vertex won't be * reassembled. Note that this specifies the * worst-case relative error between the last @@ -336,140 +325,7 @@ public: */ void computeColors(const Scalar relTol) { - if (!enablePartialReassemble_()) - return; - - ElementIterator elemIt = gridView_().template begin<0>(); - ElementIterator elemEndIt = gridView_().template end<0>(); - - // mark the red vertices and update the tolerance of the - // linearization which actually will get achieved - nextReassembleAccuracy_ = 0; - for (unsigned int i = 0; i < vertexColor_.size(); ++i) { - if (vertexDelta_[i] > relTol) - // mark vertex as red if discrepancy is larger than - // the relative tolerance - vertexColor_[i] = Red; - else - nextReassembleAccuracy_ = - std::max(nextReassembleAccuracy_, vertexDelta_[i]); - } - - // Mark all red elements - for (; elemIt != elemEndIt; ++elemIt) { - // find out whether the current element features a red - // vertex - bool isRed = false; - int numVerts = elemIt->template count<dim>(); - for (int i=0; i < numVerts; ++i) { - int globalI = vertexMapper_().map(*elemIt, i, dim); - if (vertexColor_[globalI] == Red) { - isRed = true; - break; - } - } - - // if yes, the element color is also red, else it is not - // red, i.e. green for the mean time - int globalElemIdx = elementMapper_().map(*elemIt); - if (isRed) - elementColor_[globalElemIdx] = Red; - else - elementColor_[globalElemIdx] = Green; - } - - // Mark yellow vertices (as orange for the mean time) - elemIt = gridView_().template begin<0>(); - for (; elemIt != elemEndIt; ++elemIt) { - int elemIdx = this->elementMapper_().map(*elemIt); - if (elementColor_[elemIdx] != Red) - continue; // non-red elements do not tint vertices - // yellow! - - int numVerts = elemIt->template count<dim>(); - for (int i=0; i < numVerts; ++i) { - int globalI = vertexMapper_().map(*elemIt, i, dim); - // if a vertex is already red, don't recolor it to - // yellow! - if (vertexColor_[globalI] != Red) { - vertexColor_[globalI] = Orange; - } - } - } - - // at this point we communicate the yellow vertices to the - // neighboring processes because a neigbor process may not see - // the red vertex for yellow border vertices - VertexHandleMin<EntityColor, std::vector<EntityColor>, VertexMapper> - minHandle(vertexColor_, vertexMapper_()); - gridView_().communicate(minHandle, - Dune::InteriorBorder_InteriorBorder_Interface, - Dune::ForwardCommunication); - - // Mark yellow elements - elemIt = gridView_().template begin<0>(); - for (; elemIt != elemEndIt; ++elemIt) { - int elemIdx = this->elementMapper_().map(*elemIt); - if (elementColor_[elemIdx] == Red) { - continue; // element is red already! - } - - // check whether the element features a yellow - // (resp. orange at this point) vertex - bool isYellow = false; - int numVerts = elemIt->template count<dim>(); - for (int i=0; i < numVerts; ++i) { - int globalI = vertexMapper_().map(*elemIt, i, dim); - if (vertexColor_[globalI] == Orange) { - isYellow = true; - break; - } - } - - if (isYellow) - elementColor_[elemIdx] = Yellow; - } - - // Demote orange vertices to yellow ones if it has at least - // one green element as a neighbor. - elemIt = gridView_().template begin<0>(); - for (; elemIt != elemEndIt; ++elemIt) { - int elemIdx = this->elementMapper_().map(*elemIt); - if (elementColor_[elemIdx] != Green) - continue; // yellow and red elements do not make - // orange vertices yellow! - - int numVerts = elemIt->template count<dim>(); - for (int i=0; i < numVerts; ++i) { - int globalI = vertexMapper_().map(*elemIt, i, dim); - // if a vertex is orange, recolor it to yellow! - if (vertexColor_[globalI] == Orange) - vertexColor_[globalI] = Yellow; - } - } - - // demote the border orange vertices - VertexHandleMax<EntityColor, std::vector<EntityColor>, VertexMapper> - maxHandle(vertexColor_, - vertexMapper_()); - gridView_().communicate(maxHandle, - Dune::InteriorBorder_InteriorBorder_Interface, - Dune::ForwardCommunication); - - // promote the remaining orange vertices to red - for (unsigned int i=0; i < vertexColor_.size(); ++i) { - // if a vertex is green or yellow don't do anything! - if (vertexColor_[i] == Green || vertexColor_[i] == Yellow) - continue; - - // make sure the vertex is red (this is a no-op vertices - // which are already red!) - vertexColor_[i] = Red; - - // set the error of this vertex to 0 because the system - // will be consistently linearized at this vertex - vertexDelta_[i] = 0.0; - } + asImp_().computeColors_(relTol); } /*! @@ -541,79 +397,12 @@ public: SolutionVector& residual() { return residual_; } -private: +protected: static bool enableJacobianRecycling_() { return GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnableJacobianRecycling); } static bool enablePartialReassemble_() { return GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnablePartialReassemble); } - // Construct the BCRS matrix for the global jacobian - void createMatrix_() - { - int numVerticesGlobal = gridView_().size(dim); - - // allocate raw matrix - matrix_ = new JacobianMatrix(numVerticesGlobal, numVerticesGlobal, JacobianMatrix::random); - - // find out the global indices of the neighboring vertices of - // each vertex - typedef std::set<int> NeighborSet; - std::vector<NeighborSet> neighbors(numVerticesGlobal); - ElementIterator eIt = gridView_().template begin<0>(); - const ElementIterator eEndIt = gridView_().template end<0>(); - for (; eIt != eEndIt; ++eIt) { - const Element &elem = *eIt; - int numVerticesLocal = elem.template count<dim>(); - - // if the element is not in the interior or the process - // border, all dofs just contain main-diagonal entries - if (elem.partitionType() != Dune::InteriorEntity && - elem.partitionType() != Dune::BorderEntity) - { - for (int i = 0; i < numVerticesLocal; ++i) { - int globalI = vertexMapper_().map(*eIt, i, dim); - neighbors[globalI].insert(globalI); - } - } - else - { - // loop over all element vertices - for (int i = 0; i < numVerticesLocal - 1; ++i) { - int globalI = vertexMapper_().map(*eIt, i, dim); - for (int j = i + 1; j < numVerticesLocal; ++j) { - int globalJ = vertexMapper_().map(*eIt, j, dim); - // make sure that vertex j is in the neighbor set - // of vertex i and vice-versa - neighbors[globalI].insert(globalJ); - neighbors[globalJ].insert(globalI); - } - } - } - } - - // make vertices neighbors to themselfs - for (int i = 0; i < numVerticesGlobal; ++i) { - neighbors[i].insert(i); - } - - // allocate space for the rows of the matrix - for (int i = 0; i < numVerticesGlobal; ++i) { - matrix_->setrowsize(i, neighbors[i].size()); - } - matrix_->endrowsizes(); - - // fill the rows with indices. each vertex talks to all of its - // neighbors. (it also talks to itself since vertices are - // sometimes quite egocentric.) - for (int i = 0; i < numVerticesGlobal; ++i) { - typename NeighborSet::iterator nIt = neighbors[i].begin(); - typename NeighborSet::iterator nEndIt = neighbors[i].end(); - for (; nIt != nEndIt; ++nIt) { - matrix_->addindex(i, *nIt); - } - } - matrix_->endindices(); - } // reset the global linear system of equations. if partial // reassemble is enabled, this means that the jacobian matrix must @@ -634,8 +423,7 @@ private: // reset the parts needed for Jacobian recycling if (enableJacobianRecycling_()) { - int numVerticesGlobal = matrix_->N(); - for (int i=0; i < numVerticesGlobal; ++ i) { + for (int i = 0; i < matrix_->N(); i++) { storageJacobian_[i] = 0; storageTerm_[i] = 0; } @@ -646,24 +434,22 @@ private: // reset all entries corrosponding to a red or yellow vertex for (unsigned int rowIdx = 0; rowIdx < matrix_->N(); ++rowIdx) { - if (vertexColor_[rowIdx] == Green) - continue; // the equations for this control volume are - // already below the treshold - - // here we have yellow or red vertices... - - // reset the parts needed for Jacobian recycling - if (enableJacobianRecycling_()) { - storageJacobian_[rowIdx] = 0; - storageTerm_[rowIdx] = 0; - } + if ((isBox && vertexColor_[rowIdx] != Green) + || (!isBox && elementColor_[rowIdx] != Green)) + { + // reset the parts needed for Jacobian recycling + if (enableJacobianRecycling_()) { + storageJacobian_[rowIdx] = 0; + storageTerm_[rowIdx] = 0; + } - // set all matrix entries in the row to 0 - typedef typename JacobianMatrix::ColIterator ColIterator; - ColIterator colIt = (*matrix_)[rowIdx].begin(); - const ColIterator &colEndIt = (*matrix_)[rowIdx].end(); - for (; colIt != colEndIt; ++colIt) { - (*colIt) = 0.0; + // set all matrix entries in the row to 0 + typedef typename JacobianMatrix::ColIterator ColIterator; + ColIterator colIt = (*matrix_)[rowIdx].begin(); + const ColIterator &colEndIt = (*matrix_)[rowIdx].end(); + for (; colIt != colEndIt; ++colIt) { + (*colIt) = 0.0; + } } } } @@ -677,8 +463,7 @@ private: // here and be done with it... Scalar curDt = problem_().timeManager().timeStepSize(); if (reuseMatrix_) { - int numVerticesGlobal = storageJacobian_.size(); - for (int i = 0; i < numVerticesGlobal; ++i) { + for (int i = 0; i < matrix_->N(); i++) { // rescale the mass term of the jacobian matrix MatrixBlock &J_i_i = (*matrix_)[i][i]; @@ -710,106 +495,18 @@ private: ElementIterator elemEndIt = gridView_().template end<0>(); for (; elemIt != elemEndIt; ++elemIt) { const Element &elem = *elemIt; - if (elem.partitionType() != Dune::InteriorEntity && - elem.partitionType() != Dune::BorderEntity) + if (elem.partitionType() == Dune::GhostEntity) { - assembleGhostElement_(elem); + asImp_().assembleGhostElement_(elem); } else { - assembleElement_(elem); - } - } - } - - // assemble a non-ghost element - void assembleElement_(const Element &elem) - { - if (enablePartialReassemble_()) { - int globalElemIdx = model_().elementMapper().map(elem); - if (elementColor_[globalElemIdx] == Green) { - ++greenElems_; - - assembleGreenElement_(elem); - return; - } - } - - model_().localJacobian().assemble(elem); - - int numVerticesLocal = elem.template count<dim>(); - for (int i=0; i < numVerticesLocal; ++ i) { - int globI = vertexMapper_().map(elem, i, dim); - - // update the right hand side - residual_[globI] += model_().localJacobian().residual(i); - for (int j = 0; j < residual_[globI].dimension; ++j) - assert(std::isfinite(residual_[globI][j])); - if (enableJacobianRecycling_()) { - storageTerm_[globI] += - model_().localJacobian().storageTerm(i); - } - - // only update the jacobian matrix for non-green vertices - if (vertexColor(globI) != Green) { - if (enableJacobianRecycling_()) - storageJacobian_[globI] += - model_().localJacobian().storageJacobian(i); - - // update the jacobian matrix - for (int j=0; j < numVerticesLocal; ++ j) { - int globJ = vertexMapper_().map(elem, j, dim); - (*matrix_)[globI][globJ] += - model_().localJacobian().mat(i,j); - } - } - } - } - - // "assemble" a green element. green elements only get the - // residual updated, but the jacobian is left alone... - void assembleGreenElement_(const Element &elem) - { - model_().localResidual().eval(elem); - - int numVerticesLocal = elem.template count<dim>(); - for (int i=0; i < numVerticesLocal; ++ i) { - int globI = vertexMapper_().map(elem, i, dim); - - // update the right hand side - residual_[globI] += model_().localResidual().residual(i); - if (enableJacobianRecycling_()) - storageTerm_[globI] += model_().localResidual().storageTerm(i); - } - } - - // "assemble" a ghost element - void assembleGhostElement_(const Element &elem) - { - int numVerticesLocal = elem.template count<dim>(); - for (int i=0; i < numVerticesLocal; ++i) { - const VertexPointer vp = elem.template subEntity<dim>(i); - - if (vp->partitionType() == Dune::InteriorEntity || - vp->partitionType() == Dune::BorderEntity) - { - // do not change the non-ghost vertices - continue; + asImp_().assembleElement_(elem); } - - // set main diagonal entries for the vertex - int vIdx = vertexMapper_().map(*vp); - typedef typename JacobianMatrix::block_type BlockType; - BlockType &J = (*matrix_)[vIdx][vIdx]; - for (int j = 0; j < BlockType::rows; ++j) - J[j][j] = 1.0; - - // set residual for the vertex - residual_[vIdx] = 0; } } - +protected: Problem &problem_() { return *problemPtr_; } const Problem &problem_() const @@ -844,13 +541,19 @@ private: // attributes required for partial jacobian reassembly std::vector<EntityColor> vertexColor_; std::vector<EntityColor> elementColor_; - std::vector<Scalar> vertexDelta_; + std::vector<Scalar> delta_; int totalElems_; int greenElems_; Scalar nextReassembleAccuracy_; Scalar reassembleAccuracy_; + +private: + Implementation &asImp_() + { return *static_cast<Implementation*>(this); } + const Implementation &asImp_() const + { return *static_cast<const Implementation*>(this); } }; } // namespace Dumux -- GitLab