diff --git a/dumux/boxmodels/2p/2pfluxvariables.hh b/dumux/boxmodels/2p/2pfluxvariables.hh index 4ea7096c07d4c285f68fd0dc19ac8e1bcdabc179..082d62298db5175332c4ea8370ac2e9e309516cd 100644 --- a/dumux/boxmodels/2p/2pfluxvariables.hh +++ b/dumux/boxmodels/2p/2pfluxvariables.hh @@ -58,7 +58,7 @@ class TwoPFluxVariables typedef typename GridView::ctype CoordScalar; typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVolumeVariables)) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVariables)) ElementVariables; enum { dim = GridView::dimension, @@ -77,100 +77,90 @@ class TwoPFluxVariables public: /* * \brief The constructor - * - * \param problem The problem - * \param element The finite element - * \param elemGeom The finite-volume geometry in the box scheme - * \param faceIdx The local index of the SCV (sub-control-volume) face - * \param elemDat The volume variables of the current element */ - TwoPFluxVariables(const Problem &problem, - const Element &element, - const FVElementGeometry &elemGeom, - int faceIdx, - const ElementVolumeVariables &elemDat) - : fvElemGeom_(elemGeom) - { - scvfIdx_ = faceIdx; + TwoPFluxVariables() + {} - for (int phase = 0; phase < numPhases; ++phase) { - potentialGrad_[phase] = Scalar(0); - } +#warning Docme + void update(const ElementVariables &elemVars, int scvfIdx) + { + insideScvIdx_ = elemVars.fvElemGeom().subContVolFace[scvfIdx].i; + outsideScvIdx_ = elemVars.fvElemGeom().subContVolFace[scvfIdx].j; - calculateGradients_(problem, element, elemDat); - calculateK_(problem, element, elemDat); + calculateGradients_(elemVars, scvfIdx); + calculateNormalFlux_(elemVars, scvfIdx); }; -public: - /* - * \brief Return the intrinsic permeability. + /*! + * \brief Return the extrusion factor of the SCVF. */ - const Tensor &intrinsicPermeability() const - { return K_; } + Scalar extrusionFactor() const + { return 1.0; } /*! - * \brief Return the pressure potential gradient. + * \brief Return a phase's pressure potential gradient. * * \param phaseIdx The index of the fluid phase */ const Vector &potentialGrad(int phaseIdx) const { return potentialGrad_[phaseIdx]; } + /*! + * \brief Return a phase's pressure potential gradient times + * intrinsic permeability times the normal of the sub + * control volume face times the area of the SCVF. + * + * \param phaseIdx The index of the fluid phase + */ + Scalar normalFlux(int phaseIdx) const + { return normalFlux_[phaseIdx]; } + /*! * \brief Return the local index of the downstream control volume * for a given phase as a function of the normal flux. * - * \param normalFlux The normal flux i.e. the given intrinsic permeability - * times the pressure potential gradient and SCV face normal. + * \param phaseIdx The index of the fluid phase for which the downstream + * direction is requested. */ - int downstreamIdx(Scalar normalFlux) const - { return (normalFlux >= 0)?face().j:face().i; } + int downstreamIdx(int phaseIdx) const + { return (normalFlux_[phaseIdx] > 0)?outsideScvIdx_:insideScvIdx_; } /*! * \brief Return the local index of the upstream control volume * for a given phase as a function of the normal flux. * - * \param normalFlux The normal flux i.e. the given intrinsic permeability - * times the pressure potential gradient and SCV face normal. + * \param phaseIdx The index of the fluid phase for which the upstream + * direction is requested. */ - int upstreamIdx(Scalar normalFlux) const - { return (normalFlux > 0)?face().i:face().j; } - - /*! - * \brief Return the SCV (sub-control-volume) face - */ - const SCVFace &face() const - { return fvElemGeom_.subContVolFace[scvfIdx_]; } + int upstreamIdx(int phaseIdx) const + { return (normalFlux_[phaseIdx] > 0)?insideScvIdx_:outsideScvIdx_; } protected: - const FVElementGeometry &fvElemGeom_; - int scvfIdx_; - - // gradients - Vector potentialGrad_[numPhases]; - - // intrinsic permeability - Tensor K_; - -private: - void calculateGradients_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) + void calculateGradients_(const ElementVariables &elemVars, + int scvfIdx) { + // reset all gradients to 0 + for (int phase = 0; phase < numPhases; ++phase) { + potentialGrad_[phase] = Scalar(0); + } + + typedef typename FVElementGeometry::SubControlVolumeFace Scvf; + const Scvf &scvf = elemVars.fvElemGeom().subContVolFace[scvfIdx]; + // calculate gradients - for (int idx = 0; - idx < fvElemGeom_.numVertices; - idx++) // loop over adjacent vertices + for (int scvIdx = 0; + scvIdx < elemVars.numScv(); + scvIdx ++) // loop over adjacent vertices { // FE gradient at vertex idx - const Vector &feGrad = face().grad[idx]; + const Vector &feGrad = scvf.grad[scvIdx]; // compute sum of pressure gradients for each phase for (int phase = 0; phase < numPhases; phase++) { // the pressure gradient Vector tmp(feGrad); - tmp *= elemVolVars[idx].pressure(phase); + tmp *= elemVars.volVars(scvIdx, /*historyIdx=*/0).pressure(phase); potentialGrad_[phase] += tmp; } } @@ -182,18 +172,22 @@ private: { // estimate the gravitational acceleration at a given SCV face // using the arithmetic mean - Vector g(problem.boxGravity(element, fvElemGeom_, face().i)); - g += problem.boxGravity(element, fvElemGeom_, face().j); + Vector g(elemVars.problem().boxGravity(elemVars.element(), + elemVars.fvElemGeom(), + insideScvIdx_)); + g += elemVars.problem().boxGravity(elemVars.element(), + elemVars.fvElemGeom(), + outsideScvIdx_); g /= 2; - + for (int phaseIdx=0; phaseIdx < numPhases; phaseIdx++) { // calculate the phase density at the integration point. we // only do this if the wetting phase is present in both cells - Scalar SI = elemVolVars[face().i].saturation(phaseIdx); - Scalar SJ = elemVolVars[face().j].saturation(phaseIdx); - Scalar rhoI = elemVolVars[face().i].density(phaseIdx); - Scalar rhoJ = elemVolVars[face().j].density(phaseIdx); + Scalar SI = elemVars.volVars(insideScvIdx_, /*historyIdx=*/0).saturation(phaseIdx); + Scalar SJ = elemVars.volVars(outsideScvIdx_, /*historyIdx=*/0).saturation(phaseIdx); + Scalar rhoI = elemVars.volVars(insideScvIdx_, /*historyIdx=*/0).density(phaseIdx); + Scalar rhoJ = elemVars.volVars(outsideScvIdx_, /*historyIdx=*/0).density(phaseIdx); Scalar fI = std::max(0.0, std::min(SI/1e-5, 0.5)); Scalar fJ = std::max(0.0, std::min(SJ/1e-5, 0.5)); if (fI + fJ == 0) @@ -212,20 +206,52 @@ private: } } - void calculateK_(const Problem &problem, - const Element &element, - const ElementVolumeVariables &elemVolVars) + void calculateNormalFlux_(const ElementVariables &elemVars, + int scvfIdx) { - const SpatialParameters &spatialParams = problem.spatialParameters(); + const SpatialParameters &spatialParams = elemVars.problem().spatialParameters(); + // calculate the intrinsic permeability - spatialParams.meanK(K_, - spatialParams.intrinsicPermeability(element, - fvElemGeom_, - face().i), - spatialParams.intrinsicPermeability(element, - fvElemGeom_, - face().j)); + Tensor K; + spatialParams.meanK(K, + spatialParams.intrinsicPermeability(elemVars, + insideScvIdx_), + spatialParams.intrinsicPermeability(elemVars, + outsideScvIdx_)); + + const Vector &normal = elemVars.fvElemGeom().subContVolFace[scvfIdx].normal; + + // calculate the flux in the normal direction of the + // current sub control volume face: + // + // v = - (K grad p) * n + // + // (the minus comes from the Darcy law which states that + // the flux is from high to low pressure potentials.) + Vector tmpVec; + + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + K.mv(potentialGrad(phaseIdx), tmpVec); + + // scalar product with the face normal + normalFlux_[phaseIdx] = 0.0; + for (int i = 0; i < Vector::size; ++i) + normalFlux_[phaseIdx] += tmpVec[i]*normal[i]; + + // flux is along negative pressure gradients + normalFlux_[phaseIdx] *= -1; + } } + + // local indices of the inside and the outside sub-control volumes + int insideScvIdx_; + int outsideScvIdx_; + + // gradients + Vector potentialGrad_[numPhases]; + + // normal fluxes + Scalar normalFlux_[numPhases]; }; } // end namepace diff --git a/dumux/boxmodels/2p/2plocalresidual.hh b/dumux/boxmodels/2p/2plocalresidual.hh index 0b554f26fdb2beb559e25dff62c57e86428bf911..8c45c76ba8bc1a42b0893da20ed72b049a0c8ba4 100644 --- a/dumux/boxmodels/2p/2plocalresidual.hh +++ b/dumux/boxmodels/2p/2plocalresidual.hh @@ -82,7 +82,7 @@ protected: typedef typename GET_PROP_TYPE(TypeTag, PTAG(PrimaryVariables)) PrimaryVariables; typedef typename GET_PROP_TYPE(TypeTag, PTAG(VolumeVariables)) VolumeVariables; typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluxVariables)) FluxVariables; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVolumeVariables)) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVariables)) ElementVariables; typedef Dune::FieldVector<Scalar, dimWorld> Vector; typedef Dune::FieldMatrix<Scalar, dim, dim> Tensor; @@ -107,23 +107,26 @@ public: * \param scvIdx The SCV (sub-control-volume) index * \param usePrevSol Evaluate function with solution of current or previous time step */ - void computeStorage(PrimaryVariables &result, int scvIdx, bool usePrevSol) const + void computeStorage(PrimaryVariables &result, + const ElementVariables &elemVars, + int scvIdx, + int historyIdx) const { - // if flag usePrevSol is set, the solution from the previous - // time step is used, otherwise the current solution is - // used. The secondary variables are used accordingly. This - // is required to compute the derivative of the storage term - // using the implicit euler method. - const ElementVolumeVariables &elemDat = usePrevSol ? this->prevVolVars_() : this->curVolVars_(); - const VolumeVariables &vertDat = elemDat[scvIdx]; + // retrieve the volume variables for the SCV at the specified + // point in time + const VolumeVariables &volVars = elemVars.volVars(scvIdx, historyIdx); // wetting phase mass - result[contiWEqIdx] = vertDat.density(wPhaseIdx) * vertDat.porosity() - * vertDat.saturation(wPhaseIdx); + result[contiWEqIdx] = + volVars.density(wPhaseIdx) + * volVars.porosity() + * volVars.saturation(wPhaseIdx); // non-wetting phase mass - result[contiNEqIdx] = vertDat.density(nPhaseIdx) * vertDat.porosity() - * vertDat.saturation(nPhaseIdx); + result[contiNEqIdx] = + volVars.density(nPhaseIdx) + * volVars.porosity() + * volVars.saturation(nPhaseIdx); } /*! @@ -133,16 +136,13 @@ public: * \param flux The flux over the SCV (sub-control-volume) face for each phase * \param faceIdx The index of the SCV face */ - void computeFlux(PrimaryVariables &flux, int faceIdx) const + void computeFlux(PrimaryVariables &flux, + const ElementVariables &elemVars, + int scvfIdx) const { - FluxVariables vars(this->problem_(), - this->elem_(), - this->fvElemGeom_(), - faceIdx, - this->curVolVars_()); flux = 0; - asImp_()->computeAdvectiveFlux(flux, vars); - asImp_()->computeDiffusiveFlux(flux, vars); + asImp_()->computeAdvectiveFlux(flux, elemVars, scvfIdx); + asImp_()->computeDiffusiveFlux(flux, elemVars, scvfIdx); } /*! @@ -155,31 +155,40 @@ public: * This method is called by compute flux and is mainly there for * derived models to ease adding equations selectively. */ - void computeAdvectiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const + void computeAdvectiveFlux(PrimaryVariables &flux, + const ElementVariables &elemVars, + int scvfIdx) const { + const FluxVariables &fluxVars = elemVars.fluxVars(scvfIdx); + const FluxVariables &evalPointFluxVars = elemVars.evalPointFluxVars(scvfIdx); + //////// // advective fluxes of all components in all phases //////// Vector tmpVec; for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - // calculate the flux in the normal direction of the + // data attached to upstream and the downstream vertices + // of the current phase. The upstream decision has to be + // made using the evaluation point and *not* the current + // solution. (although the actual secondary variables must + // obviously come from the current solution.) + int upIdx = evalPointFluxVars.upstreamIdx(phaseIdx); + int dnIdx = evalPointFluxVars.downstreamIdx(phaseIdx); + const VolumeVariables &up = elemVars.volVars(upIdx, /*historyIdx=*/0); + const VolumeVariables &dn = elemVars.volVars(dnIdx, /*historyIdx=*/0); + + // retrieve the 'velocity' in the normal direction of the // current sub control volume face: // - // v = - (K grad p) * n + // v_\alpha := - (K grad p) * n // - // (the minus comes from the Darcy law which states that - // the flux is from high to low pressure potentials.) - fluxVars.intrinsicPermeability().mv(fluxVars.potentialGrad(phaseIdx), tmpVec); - Scalar normalFlux = 0; - for (int i = 0; i < Vector::size; ++i) - normalFlux += tmpVec[i]*fluxVars.face().normal[i]; - normalFlux *= -1; - - // data attached to upstream and the downstream vertices - // of the current phase - const VolumeVariables &up = this->curVolVars_(fluxVars.upstreamIdx(normalFlux)); - const VolumeVariables &dn = this->curVolVars_(fluxVars.downstreamIdx(normalFlux)); + // note that v_\alpha is *not* equivalent to the Darcy + // velocity because the relative permebility is not + // included. Its purpose is to make the upwind decision, + // i.e. to decide whether the flow goes from sub control + // volume i to j or vice versa. + Scalar normalFlux = fluxVars.normalFlux(phaseIdx); // add advective flux of current component in current // phase @@ -204,10 +213,11 @@ public: * non-isothermal two-phase models to calculate diffusive heat * fluxes */ - void computeDiffusiveFlux(PrimaryVariables &flux, const FluxVariables &fluxData) const + void computeDiffusiveFlux(PrimaryVariables &flux, + const ElementVariables &elemVars, + int scvfIdx) const { - // diffusive fluxes - flux += 0.0; + // no diffusive fluxes for immiscible models } /*! @@ -217,14 +227,12 @@ public: * \param localVertexIdx The index of the SCV * */ - void computeSource(PrimaryVariables &q, int localVertexIdx) const + void computeSource(PrimaryVariables &values, + const ElementVariables &elemVars, + int scvIdx) const { // retrieve the source term intrinsic to the problem - this->problem_().boxSDSource(q, - this->elem_(), - this->fvElemGeom_(), - localVertexIdx, - this->curVolVars_()); + elemVars.problem().source(values, elemVars, scvIdx); } diff --git a/dumux/boxmodels/2p/2pmodel.hh b/dumux/boxmodels/2p/2pmodel.hh index 604d538d0d87294433bc5962c4fa453089356518..8c2126b9a3f41d834be180f831b9c798f75174f9 100644 --- a/dumux/boxmodels/2p/2pmodel.hh +++ b/dumux/boxmodels/2p/2pmodel.hh @@ -93,7 +93,7 @@ class TwoPModel : public BoxModel<TypeTag> typedef typename GET_PROP_TYPE(TypeTag, PTAG(SolutionVector)) SolutionVector; typedef typename GET_PROP_TYPE(TypeTag, PTAG(TwoPIndices)) Indices; typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluxVariables)) FluxVariables; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVolumeVariables)) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVariables)) ElementVariables; enum { @@ -122,8 +122,11 @@ public: */ Scalar primaryVarWeight(int globalVertexIdx, int pvIdx) const { - if (Indices::pressureIdx == pvIdx) - return std::min(10.0/this->prevSol()[globalVertexIdx][pvIdx], 1.0); + if (Indices::pressureIdx == pvIdx) { + Scalar absPv = + std::abs(this->solution(/*historyIdx=*/1)[globalVertexIdx][pvIdx]); + return std::min(10.0/absPv, 1.0); + } return 1; } @@ -173,9 +176,7 @@ public: unsigned numElements = this->gridView_().size(0); ScalarField *rank = writer.allocateManagedBuffer(numElements); - FVElementGeometry fvElemGeom; - VolumeVariables volVars; - ElementVolumeVariables elemVolVars; + ElementVariables elemVars(this->problem_()); ElementIterator elemIt = this->gridView_().template begin<0>(); ElementIterator elemEndIt = this->gridView_().template end<0>(); @@ -188,19 +189,14 @@ public: int idx = this->elementMapper().map(*elemIt); (*rank)[idx] = this->gridView_().comm().rank(); - fvElemGeom.update(this->gridView_(), *elemIt); + elemVars.updateFVElemGeom(*elemIt); + elemVars.updateScvVars(/*historyIdx=*/0); - int numVerts = elemIt->template count<dim> (); - for (int i = 0; i < numVerts; ++i) + for (int scvIdx = 0; scvIdx < elemVars.numScv(); ++scvIdx) { - int globalIdx = this->vertexMapper().map(*elemIt, i, dim); - volVars.update(sol[globalIdx], - this->problem_(), - *elemIt, - fvElemGeom, - i, - false); + int globalIdx = this->vertexMapper().map(*elemIt, scvIdx, dim); + const VolumeVariables &volVars = elemVars.volVars(scvIdx, /*historyIdx=*/0); (*pW)[globalIdx] = volVars.pressure(wPhaseIdx); (*pN)[globalIdx] = volVars.pressure(nPhaseIdx); (*pC)[globalIdx] = volVars.capillaryPressure(); @@ -218,6 +214,7 @@ public: } }; +#if 0 if(velocityOutput) { // calculate vertex velocities @@ -273,6 +270,7 @@ public: // Transformation of the global normal vector to normal vector in the reference element const Dune::FieldMatrix<CoordScalar, dim, dim> jacobianT1 = elemIt->geometry().jacobianTransposed(localPosIP); + elemIt->geometry().jacobianTransposed(localPosIP); GlobalPosition localNormal(0); jacobianT1.mv(globalNormal, localNormal); @@ -331,7 +329,9 @@ public: (*velocityN)[globalIdx] += scvVelocity; } } +#endif } +#if 0 if(velocityOutput) { // divide the vertex velocities by the number of adjacent scvs i.e. cells @@ -340,7 +340,7 @@ public: (*velocityN)[globalIdx] /= (*cellNum)[globalIdx]; } } - +#endif writer.attachVertexData(*Sn, "Sn"); writer.attachVertexData(*Sw, "Sw"); writer.attachVertexData(*pN, "pn"); @@ -352,11 +352,13 @@ public: writer.attachVertexData(*mobN, "mobN"); writer.attachVertexData(*poro, "porosity"); writer.attachVertexData(*Te, "temperature"); +#if 0 if(velocityOutput) // check if velocity output is demanded { writer.attachVertexData(*velocityW, "velocityW", dim); writer.attachVertexData(*velocityN, "velocityN", dim); } +#endif writer.attachCellData(*rank, "process rank"); } }; diff --git a/dumux/boxmodels/2p/2pproblem.hh b/dumux/boxmodels/2p/2pproblem.hh index 6981be5acc2f130a392677a9fa65c720929c1003..bb30c5d275166b2197d61e3679a6a4d0ef24a764 100644 --- a/dumux/boxmodels/2p/2pproblem.hh +++ b/dumux/boxmodels/2p/2pproblem.hh @@ -111,6 +111,26 @@ public: */ // \{ + /*! + * \brief Returns the temperature \f$\mathrm{[K]}\f$ within a control volume. + * + * \param context Container for the volume variables, element, + * fvElementGeometry, etc + * \param localIdx The local index of the sub control volume inside + * the element + */ + template <class Context> + // if you get an deprecated warning here, please use context + // objects to specify your problem! + DUNE_DEPRECATED + Scalar temperature(const Context &context, + int localIdx) const + { + return asImp_().boxTemperature(context.element(), + context.fvElemGeom(), + localIdx); + }; + /*! * \brief Returns the temperature \f$\mathrm{[K]}\f$ within a control volume. * @@ -125,6 +145,7 @@ public: Scalar boxTemperature(const Element &element, const FVElementGeometry fvGeom, int scvIdx) const + DUNE_DEPRECATED // use context objects! { return asImp_().temperatureAtPos(fvGeom.subContVol[scvIdx].global); } /*! @@ -136,6 +157,7 @@ public: * \param pos The position in global coordinates where the temperature should be specified. */ Scalar temperatureAtPos(const GlobalPosition &pos) const + DUNE_DEPRECATED // use context objects! { return asImp_().temperature(); } /*! @@ -146,8 +168,30 @@ public: * no energy equation is used. */ Scalar temperature() const + DUNE_DEPRECATED // use context objects! { DUNE_THROW(Dune::NotImplemented, "temperature() method not implemented by the actual problem"); }; + + /*! + * \brief Returns the acceleration due to gravity \f$\mathrm{[m/s^2]}\f$. + * + * \param context Container for the volume variables, element, + * fvElementGeometry, etc + * \param localIdx The local index of the sub control volume inside + * the element + */ + template <class Context> + // if you get an deprecated warning here, please use context + // objects to specify your problem! + DUNE_DEPRECATED + const Vector &gravity(const Context &context, + int localIdx) const + { + return asImp_().boxGravity(context.element(), + context.fvElemGeom(), + localIdx); + }; + /*! * \brief Returns the acceleration due to gravity \f$\mathrm{[m/s^2]}\f$. * @@ -155,8 +199,9 @@ public: * it just calls gravityAtPos(). */ const Vector &boxGravity(const Element &element, - const FVElementGeometry &fvGeom, - int scvIdx) const + const FVElementGeometry &fvGeom, + int scvIdx) const + DUNE_DEPRECATED // use context objects! { return asImp_().gravityAtPos(fvGeom.subContVol[scvIdx].global); } /*! diff --git a/dumux/boxmodels/2p/2pvolumevariables.hh b/dumux/boxmodels/2p/2pvolumevariables.hh index 8612933a7e4ad1a204ccd5deb2d18fe7f2a60262..52391ab80b82605d9c05af62eae5289ddd974dea 100644 --- a/dumux/boxmodels/2p/2pvolumevariables.hh +++ b/dumux/boxmodels/2p/2pvolumevariables.hh @@ -56,6 +56,8 @@ class TwoPVolumeVariables : public BoxVolumeVariables<TypeTag> typedef typename GET_PROP_TYPE(TypeTag, PTAG(MaterialLawParams)) MaterialLawParams; typedef typename GET_PROP_TYPE(TypeTag, PTAG(FVElementGeometry)) FVElementGeometry; typedef typename GET_PROP_TYPE(TypeTag, PTAG(PrimaryVariables)) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVariables)) ElementVariables; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(SpatialParameters)) SpatialParameters; typedef typename GET_PROP_TYPE(TypeTag, PTAG(TwoPIndices)) Indices; enum { @@ -89,28 +91,26 @@ public: * \param isOldSol Evaluate function with solution of current or previous time step */ void update(const PrimaryVariables &priVars, - const Problem &problem, - const Element &element, - const FVElementGeometry &elemGeom, + const ElementVariables &elemVars, int scvIdx, - bool isOldSol) + int historyIdx) { ParentType::update(priVars, - problem, - element, - elemGeom, + elemVars, scvIdx, - isOldSol); + historyIdx); asImp().updateTemperature_(priVars, - element, - elemGeom, + elemVars, scvIdx, - problem); + historyIdx); - // material law parameters + const SpatialParameters &spatialParams = + elemVars.problem().spatialParameters(); + + // material law parameters const MaterialLawParams &materialParams = - problem.spatialParameters().materialLawParams(element, elemGeom, scvIdx); + spatialParams.materialLawParams(elemVars, scvIdx); Scalar p[numPhases]; Scalar Sn; @@ -147,9 +147,7 @@ public: fluidState_); // porosity - porosity_ = problem.spatialParameters().porosity(element, - elemGeom, - scvIdx); + porosity_ = spatialParams.porosity(elemVars, scvIdx); } /*! @@ -218,12 +216,12 @@ public: protected: void updateTemperature_(const PrimaryVariables &priVars, - const Element &element, - const FVElementGeometry &elemGeom, + const ElementVariables &elemVars, int scvIdx, - const Problem &problem) + int historyIdx) { - temperature_ = problem.boxTemperature(element, elemGeom, scvIdx); + temperature_ = + elemVars.problem().temperature(elemVars, scvIdx); } FluidState fluidState_; diff --git a/dumux/boxmodels/common/boxassembler.hh b/dumux/boxmodels/common/boxassembler.hh index 045ad46f77fd5b9033efc95b492d44fb60eb403e..ef31386e032977419c8bd9438fe49eddef70a7b5 100644 --- a/dumux/boxmodels/common/boxassembler.hh +++ b/dumux/boxmodels/common/boxassembler.hh @@ -113,9 +113,6 @@ public: BoxAssembler() { - enableJacobianRecycling_ = GET_PARAM(TypeTag, bool, EnableJacobianRecycling); - enablePartialReassemble_ = GET_PARAM(TypeTag, bool, EnablePartialReassemble); - problemPtr_ = 0; matrix_ = 0; @@ -159,7 +156,7 @@ public: // 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_) { + if (enableJacobianRecycling_()) { storageJacobian_.resize(numVerts); storageTerm_.resize(numVerts); } @@ -167,7 +164,7 @@ public: totalElems_ = gridView_().comm().sum(numElems); // initialize data needed for partial reassembly - if (enablePartialReassemble_) { + if (enablePartialReassemble_()) { vertexColor_.resize(numVerts); vertexDelta_.resize(numVerts); elementColor_.resize(numElems); @@ -176,14 +173,14 @@ public: } /*! - * \brief Assemble the local jacobian of the problem. + * \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_; + bool printReassembleStatistics = enablePartialReassemble_() && !reuseMatrix_; int succeeded; try { assemble_(); @@ -231,7 +228,7 @@ public: */ void setMatrixReuseable(bool yesno = true) { - if (enableJacobianRecycling_) + if (enableJacobianRecycling_()) reuseMatrix_ = yesno; } @@ -247,7 +244,7 @@ public: // do not use partial reassembly for the next iteration nextReassembleAccuracy_ = 0.0; - if (enablePartialReassemble_) { + if (enablePartialReassemble_()) { std::fill(vertexColor_.begin(), vertexColor_.end(), Red); @@ -283,7 +280,7 @@ public: void updateDiscrepancy(const SolutionVector &u, const SolutionVector &uDelta) { - if (!enablePartialReassemble_) + if (!enablePartialReassemble_()) return; // update the vector with the distances of the current @@ -342,7 +339,7 @@ public: */ void computeColors(Scalar relTol) { - if (!enablePartialReassemble_) + if (!enablePartialReassemble_()) return; ElementIterator elemIt = gridView_().template begin<0>(); @@ -486,7 +483,7 @@ public: */ int vertexColor(const Element &element, int vertIdx) const { - if (!enablePartialReassemble_) + if (!enablePartialReassemble_()) return Red; // reassemble unconditionally! int globalIdx = vertexMapper_().map(element, vertIdx, dim); @@ -500,7 +497,7 @@ public: */ int vertexColor(int globalVertIdx) const { - if (!enablePartialReassemble_) + if (!enablePartialReassemble_()) return Red; // reassemble unconditionally! return vertexColor_[globalVertIdx]; } @@ -512,7 +509,7 @@ public: */ int elementColor(const Element &element) const { - if (!enablePartialReassemble_) + if (!enablePartialReassemble_()) return Red; // reassemble unconditionally! int globalIdx = elementMapper_().map(element); @@ -526,7 +523,7 @@ public: */ int elementColor(int globalElementIdx) const { - if (!enablePartialReassemble_) + if (!enablePartialReassemble_()) return Red; // reassemble unconditionally! return elementColor_[globalElementIdx]; } @@ -543,8 +540,27 @@ public: const SolutionVector& residual() const { return residual_; } - private: + static bool enableJacobianRecycling_() + { return GET_PARAM(TypeTag, bool, EnableJacobianRecycling); } + static bool enablePartialReassemble_() + { return GET_PARAM(TypeTag, bool, EnablePartialReassemble); } + + 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(); } + // Construct the BCRS matrix for the global jacobian void createMatrix_() { @@ -623,7 +639,7 @@ private: // always reset the right hand side. residual_ = 0.0; - if (!enablePartialReassemble_) { + if (!enablePartialReassemble_()) { // If partial reassembly of the jacobian is not enabled, // we can just reset everything! (*matrix_) = 0; @@ -740,21 +756,20 @@ private: residual_[globI] += model_().localJacobian().residual(i); if (enableJacobianRecycling_) { - // save the flux term and the jacobian of the - // storage term in case we can reuse the current - // linearization... + // save storage term and its Jacobian in case we can + // reuse the current linearization... storageJacobian_[globI] += - model_().localJacobian().storageJacobian(i); + model_().localJacobian().jacobianStorage(i); storageTerm_[globI] += - model_().localJacobian().storageTerm(i); + model_().localJacobian().residualStorage(i); } // update the jacobian matrix for (int j=0; j < numVertices; ++ j) { int globJ = vertexMapper_().map(elem, j, dim); (*matrix_)[globI][globJ] += - model_().localJacobian().mat(i,j); + model_().localJacobian().jacobian(i, j); } } } @@ -785,22 +800,6 @@ private: } } - - 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 @@ -827,9 +826,6 @@ private: Scalar nextReassembleAccuracy_; Scalar reassembleAccuracy_; - - bool enableJacobianRecycling_; - bool enablePartialReassemble_; }; } // namespace Dumux diff --git a/dumux/boxmodels/common/boxelementvolumevariables.hh b/dumux/boxmodels/common/boxelementvolumevariables.hh index 8e692ab0d072b8e8e4d6446f7f3ac915241082a6..63ac9daf88d3e2406c314304cf51db6e79da28a6 100644 --- a/dumux/boxmodels/common/boxelementvolumevariables.hh +++ b/dumux/boxmodels/common/boxelementvolumevariables.hh @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (C) 2010 by Andreas Lauser * + * Copyright (C) 2010-2011 by Andreas Lauser * * Institute of Hydraulic Engineering * * University of Stuttgart, Germany * * email: <givenname>.<name>@iws.uni-stuttgart.de * @@ -22,8 +22,8 @@ * * \brief Volume variables gathered on an element */ -#ifndef DUMUX_BOX_ELEMENT_VOLUME_VARIABLES_HH -#define DUMUX_BOX_ELEMENT_VOLUME_VARIABLES_HH +#ifndef DUMUX_BOX_ELEMENT_VARIABLES_HH +#define DUMUX_BOX_ELEMENT_VARIABLES_HH #include "boxproperties.hh" @@ -38,16 +38,28 @@ namespace Dumux * volume variables object for each of the element's vertices */ template<class TypeTag> -class BoxElementVolumeVariables : public std::vector<typename GET_PROP_TYPE(TypeTag, PTAG(VolumeVariables)) > +class BoxElementVariables { typedef typename GET_PROP_TYPE(TypeTag, PTAG(VolumeVariables)) VolumeVariables; - typedef std::vector<VolumeVariables> ParentType; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(FluxVariables)) FluxVariables; + + // the history size of the time discretization in number of steps + enum { timeDiscHistorySize = GET_PROP_VALUE(TypeTag, PTAG(TimeDiscHistorySize)) }; + + struct ScvStore_ { + VolumeVariables volVars[timeDiscHistorySize]; + VolumeVariables bcTypes; + }; + typedef std::vector<ScvStore_> ScvVarsVector; + typedef std::vector<FluxVariables> ScvfVarsVector; typedef typename GET_PROP_TYPE(TypeTag, PTAG(Scalar)) Scalar; typedef typename GET_PROP_TYPE(TypeTag, PTAG(Problem)) Problem; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(Model)) Model; typedef typename GET_PROP_TYPE(TypeTag, PTAG(FVElementGeometry)) FVElementGeometry; typedef typename GET_PROP_TYPE(TypeTag, PTAG(SolutionVector)) SolutionVector; typedef typename GET_PROP_TYPE(TypeTag, PTAG(VertexMapper)) VertexMapper; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(BoundaryTypes)) BoundaryTypes; typedef typename GET_PROP_TYPE(TypeTag, PTAG(PrimaryVariables)) PrimaryVariables; typedef typename GET_PROP_TYPE(TypeTag, PTAG(GridView)) GridView; @@ -57,47 +69,107 @@ class BoxElementVolumeVariables : public std::vector<typename GET_PROP_TYPE(Type enum { dim = GridView::dimension }; enum { numEq = GET_PROP_VALUE(TypeTag, PTAG(NumEq)) }; + typedef Dune::FieldVector<Scalar, dim> GlobalPosition; + public: /*! * \brief The constructor. */ - BoxElementVolumeVariables() - { } + explicit BoxElementVariables(const Problem &problem) + : gridView_(problem.gridView()) + { + // remember the problem object + problemPtr_ = &problem; + modelPtr_ = &problem.model(); + } /*! - * \brief Construct the volume variables for all of vertices of an element. + * \brief Construct the volume variables of an element from scratch. * * \param problem The problem which needs to be simulated. * \param element The DUNE Codim<0> entity for which the volume variables ought to be calculated - * \param fvElemGeom The finite volume geometry of the element - * \param oldSol Tells whether the model's previous or current solution should be used. */ - void update(const Problem &problem, - const Element &element, - const FVElementGeometry &fvElemGeom, - bool oldSol) + void updateAll(const Element &elem) + { + updateFVElemGeom(elem); + updateBoundaryTypes(); + updateAllScvVars(); + updateAllScvfVars(); + } + + void updateFVElemGeom(const Element &elem) + { + // remember the current element + elemPtr_ = &elem; + + // update the finite element geometry + fvElemGeom_.update(gridView_, elem); + } + + void updateBoundaryTypes() { - const SolutionVector &globalSol = - oldSol? - problem.model().prevSol(): - problem.model().curSol(); - const VertexMapper &vertexMapper = problem.vertexMapper(); - // we assert that the i-th shape function is - // associated to the i-th vert of the element. - int n = element.template count<dim>(); - this->resize(n); - for (int i = 0; i < n; i++) { - const PrimaryVariables &solI - = globalSol[vertexMapper.map(element, i, dim)]; - (*this)[i].update(solI, - problem, - element, - fvElemGeom, - i, - oldSol); + // resize the SCV and the SCVF arrays + if (fvElemGeom_.numVertices > scvVars_.size()) { + scvVars_.resize(fvElemGeom_.numVertices); + boundaryTypes_.resize(fvElemGeom_.numVertices); } + if (fvElemGeom_.numEdges > scvfVars_.size()) + scvfVars_.resize(fvElemGeom_.numEdges); + + // fill the boundary types stuff + hasNeumann_ = false; + hasDirichlet_ = false; + for (int scvIdx = 0; scvIdx < numScv(); ++scvIdx) { + int globalIdx = model().vertexMapper().map(element(), scvIdx, dim); + boundaryTypes_[scvIdx] = model().boundaryTypes(globalIdx); + hasDirichlet_ = hasDirichlet_ || boundaryTypes_[scvIdx]->hasDirichlet(); + hasNeumann_ = hasNeumann_ || boundaryTypes_[scvIdx]->hasNeumann(); + } + + // set the default evaluation points + scvIdxSaved_ = -1; + scvfVarsEval_ = &scvfVars_; + } + + void updateAllScvVars() + { + for (int historyIdx = 0; historyIdx < timeDiscHistorySize; ++ historyIdx) + updateScvVars(historyIdx); }; + void updateScvVars(int historyIdx) + { + // update the volume variables for the whole history + const VertexMapper &vertexMapper = problem().vertexMapper(); + const SolutionVector &globalSol = model().solution(historyIdx); + + // set the hints for the volume variables + model().setHints(*this, historyIdx); + + int nScv = numScv(); + for (int scvIdx = 0; scvIdx < nScv; scvIdx++) { + const PrimaryVariables &scvSol + = globalSol[vertexMapper.map(element(), scvIdx, dim)]; + updateScvVars(scvSol, scvIdx, historyIdx); + } + }; + + void updateScvVars(const PrimaryVariables &priVars, int scvIdx, int historyIdx) + { + scvVars_[scvIdx].volVars[historyIdx].update(priVars, + /*context=*/*this, + scvIdx, + historyIdx); + } + + void updateAllScvfVars() + { + for (int scvfIdx = 0; scvfIdx < numScvf(); scvfIdx++) { + scvfVars_[scvfIdx].update(/*context=*/ *this, + /*localIndex=*/scvfIdx); + } + } + /*! * \brief Construct the volume variables for all of vertices of an * element given a solution vector computed by PDELab. @@ -112,27 +184,216 @@ public: * \param elementSolVector The local solution for the element using PDELab ordering */ template<typename ElemSolVectorType> - void updatePDELab(const Problem &problem, - const Element &element, - const FVElementGeometry &fvElemGeom, - const ElemSolVectorType& elementSolVector) + void updatePDELab(const Element &element, + const ElemSolVectorType &elementSolVector) { - int n = element.template count<dim>(); - this->resize(n); - for (int vertexIdx = 0; vertexIdx < n; vertexIdx++) + updateFVElemGeom(element); + updateBoundaryTypes(element); + + // update the current time step's volume variables + PrimaryVariables scvSol; + for (int scvIdx = 0; scvIdx < numScv(); scvIdx++) { - PrimaryVariables solI(0); - for (int eqnIdx=0; eqnIdx<numEq; eqnIdx++) - solI[eqnIdx] = elementSolVector[vertexIdx + eqnIdx*n]; - (*this)[vertexIdx].update(solI, - problem, - element, - fvElemGeom, - vertexIdx, - false); + // reorder the solution + for (int eqnIdx = 0; eqnIdx < numEq; eqnIdx++) + scvSol[eqnIdx] = elementSolVector[scvIdx + eqnIdx*numScv()]; + // update the volume variables for the newest history index + updateScvVars_(scvSol, /*historyIdx=*/0, scvIdx); } }; + + /*! + * \brief Return a reference to the problem. + */ + const Problem &problem() const + { return *problemPtr_; } + + /*! + * \brief Return a reference to the model. + */ + const Model &model() const + { return *modelPtr_; } + + /*! + * \brief Return a reference to the grid view. + */ + const GridView &gridView() const + { return gridView_; } + + /*! + * \brief Return the current element. + */ + const Element &element() const + { return *elemPtr_; } + + /*! + * \brief Return the number of sub-control volumes of the current element. + */ + int numScv() const + { return fvElemGeom_.numVertices; } + + /*! + * \brief Return the number of sub-control volume faces of the current element. + */ + int numScvf() const + { return fvElemGeom_.numEdges; } + + /*! + * \brief Return the current finite element geometry. + */ + const FVElementGeometry &fvElemGeom() const + { return fvElemGeom_; } + + /*! + * \brief Return the position of a local entities in global coordinates + */ + const GlobalPosition &pos(int scvIdx) const + { return fvElemGeom_.subContVol[scvIdx].global; } + + /*! + * \brief Returns whether the current element is on the domain's + * boundary. + */ + bool onBoundary() const + { return hasNeumann_ || hasDirichlet_; }; + + /*! + * \brief Returns whether the current element has a Neumann boundary segment. + */ + bool hasNeumann() const + { return hasNeumann_; }; + + /*! + * \brief Returns whether the current element has a Dirichlet vertex + */ + bool hasDirichlet() const + { return hasDirichlet_; }; + + /*! + * \brief Returns the boundary types for a given vertex + */ + const BoundaryTypes &boundaryTypes(int scvIdx) const + { + return *boundaryTypes_[scvIdx]; + } + + /*! + * \brief Save the current flux variables and use them as the + * evaluation point. + */ + void saveScvfVars() + { + scvfVarsSaved_ = scvfVars_; + + // change evaluation point + scvfVarsEval_ = &scvfVarsSaved_; + } + + /*! + * \brief Restore current flux variables from the saved ones. + */ + void restoreScvfVars() + { + //scvfVarsSaved_ = scvfVars_; // not needed + + // change evaluation point + scvfVarsEval_ = &scvfVars_; + } + + /*! + * \brief Return a reference to the volume variables of a + * sub-control volume at a given time. + * + * If the time step index is not given, return the volume + * variables for the current time. + * + * \param scvIdx The local index of the sub-control volume for + * which the volume variables are requested + * \param historyIdx The index of the time step for which the + * volume variables are requested. 0 means + * current time step, 1 previous time step, + * 2 next-to-previous, etc. + */ + const VolumeVariables &volVars(int scvIdx, int historyIdx = 0) const + { return scvVars_[scvIdx].volVars[historyIdx]; } + + /*! + * \copydoc volVars() + */ + VolumeVariables &volVars(int scvIdx, int historyIdx = 0) + { return scvVars_[scvIdx].volVars[historyIdx]; } + + /*! + * \brief Returns the volume variables at the evaluation point. + */ + void saveScvVars(int scvIdx) + { + scvIdxSaved_ = scvIdx; + scvVarsSaved_ = scvVars_[scvIdx].volVars[/*historyIdx=*/0]; + } + + /*! + * \brief Restores the volume variables at the evaluation point. + */ + void restoreScvVars(int scvIdx) + { + scvIdxSaved_ = -1; + scvVars_[scvIdx].volVars[/*historyIdx=*/0] = scvVarsSaved_; + } + + /*! + * \brief Return a reference to the flux variables of a + * sub-control volume face. + * + * \param scvfIdx The local index of the sub-control volume face for + * which the flux variables are requested + */ + const FluxVariables &fluxVars(int scvIdx) const + { return scvfVars_[scvIdx]; } + + /*! + * \brief Return a reference to the flux variables of a + * sub-control volume face for the evaluation point. + * + * \param scvfIdx The local index of the sub-control volume face for + * which the flux variables are requested + */ + const FluxVariables &evalPointFluxVars(int scvfIdx) const + { + return (*scvfVarsEval_)[scvfIdx]; + } + + /*! + * \brief Returns the volume variables for history index 0 at the + * evaluation point. + */ + const VolumeVariables &evalPointVolVars(int scvIdx) const + { + if (scvIdxSaved_ == scvIdx) + return scvVarsSaved_; + return volVars(scvIdx, /*historyIdx=*/0); + } + +protected: + ScvVarsVector scvVars_; + + int scvIdxSaved_; + VolumeVariables scvVarsSaved_; + + ScvfVarsVector scvfVars_; + ScvfVarsVector scvfVarsSaved_; + + ScvfVarsVector *scvfVarsEval_; + + const Problem *problemPtr_; + const Model *modelPtr_; + const Element *elemPtr_; + const GridView gridView_; + FVElementGeometry fvElemGeom_; + bool hasNeumann_; + bool hasDirichlet_; + std::vector<const BoundaryTypes*> boundaryTypes_; }; } // namespace Dumux diff --git a/dumux/boxmodels/common/boxlocaljacobian.hh b/dumux/boxmodels/common/boxlocaljacobian.hh index 9ccf1ffed81e285d28b74674d5e9d9fcff0eeab8..05fee5964a1c63a6dcf78e22c55fb9cbb0720c4b 100644 --- a/dumux/boxmodels/common/boxlocaljacobian.hh +++ b/dumux/boxmodels/common/boxlocaljacobian.hh @@ -30,6 +30,7 @@ #ifndef DUMUX_BOX_LOCAL_JACOBIAN_HH #define DUMUX_BOX_LOCAL_JACOBIAN_HH +#include <dune/istl/bvector.hh> #include <dune/istl/matrix.hh> #include "boxelementboundarytypes.hh" @@ -77,17 +78,12 @@ private: typedef typename GET_PROP_TYPE(TypeTag, PTAG(Problem)) Problem; typedef typename GET_PROP_TYPE(TypeTag, PTAG(Model)) Model; typedef typename GET_PROP_TYPE(TypeTag, PTAG(GridView)) GridView; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(JacobianAssembler)) JacobianAssembler; enum { numEq = GET_PROP_VALUE(TypeTag, PTAG(NumEq)), dim = GridView::dimension, dimWorld = GridView::dimensionworld, - - Red = JacobianAssembler::Red, - Yellow = JacobianAssembler::Yellow, - Green = JacobianAssembler::Green, }; @@ -113,22 +109,29 @@ private: typedef typename GET_PROP_TYPE(TypeTag, PTAG(PrimaryVariables)) PrimaryVariables; typedef typename GET_PROP_TYPE(TypeTag, PTAG(VolumeVariables)) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVolumeVariables)) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVariables)) ElementVariables; typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementBoundaryTypes)) ElementBoundaryTypes; typedef Dune::FieldMatrix<Scalar, numEq, numEq> MatrixBlock; typedef Dune::Matrix<MatrixBlock> LocalBlockMatrix; + typedef Dune::FieldVector<Scalar, numEq> VectorBlock; + typedef Dune::BlockVector<VectorBlock> LocalBlockVector; + typedef Dune::BlockVector<MatrixBlock> LocalStorageMatrix; + // copying a local jacobian is not a good idea BoxLocalJacobian(const BoxLocalJacobian &); public: BoxLocalJacobian() - { - numericDifferenceMethod_ = GET_PARAM(TypeTag, int, NumericDifferenceMethod); - Valgrind::SetUndefined(problemPtr_); + { + internalElemVars_ = 0; } + ~BoxLocalJacobian() + { + delete internalElemVars_; + } /*! * \brief Initialize the local Jacobian object. @@ -139,139 +142,66 @@ public: * \param prob The problem which we want to simulate. */ void init(Problem &prob) - { + { problemPtr_ = &prob; - localResidual_.init(prob); - - // assume quadrilinears as elements with most vertices - A_.setSize(2<<dim, 2<<dim); - storageJacobian_.resize(2<<dim); + modelPtr_ = &prob.model(); + internalElemVars_ = new ElementVariables(prob); } /*! * \brief Assemble an element's local Jacobian matrix of the * defect. * - * \param element The DUNE Codim<0> entity which we look at. + * This assembles the 'grad f(x^k)' and 'f(x^k)' part of the newton update */ void assemble(const Element &element) { - // set the current grid element and update the element's - // finite volume geometry - elemPtr_ = &element; - fvElemGeom_.update(gridView_(), element); - reset_(); - - bcTypes_.update(problem_(), elem_(), fvElemGeom_); - - // this is pretty much a HACK because the internal state of - // the problem is not supposed to be changed during the - // evaluation of the residual. (Reasons: It is a violation of - // abstraction, makes everything more prone to errors and is - // not thread save.) The real solution are context objects! - problem_().updateCouplingParams(elem_()); - - // set the hints for the volume variables - model_().setHints(element, prevVolVars_, curVolVars_); - - // update the secondary variables for the element at the last - // and the current time levels - prevVolVars_.update(problem_(), - elem_(), - fvElemGeom_, - true /* isOldSol? */); - - curVolVars_.update(problem_(), - elem_(), - fvElemGeom_, - false /* isOldSol? */); - - // update the hints of the model - model_().updateCurHints(element, curVolVars_); + internalElemVars_->updateAll(element); + assemble(*internalElemVars_); + } + + /*! + * \brief Assemble an element's local Jacobian matrix of the + * defect, given all secondary variables for the element. + * + * After calling this method the ElementVariables are in undefined + * state, so do not use it anymore! + */ + void assemble(ElementVariables &elemVars) + { + // update the weights of the primary variables using the + // current element variables + model_().updatePVWeights(elemVars); + + resize_(elemVars); + reset_(elemVars); + // calculate the local residual - localResidual().eval(elem_(), - fvElemGeom_, - prevVolVars_, - curVolVars_, - bcTypes_); - residual_ = localResidual().residual(); - storageTerm_ = localResidual().storageTerm(); + localResidual_.eval(residual_, residualStorage_, elemVars); - model_().updatePVWeights(elem_(), curVolVars_); + // save all flux variables calculated using the unmodified + // primary variables. This automatically makes these flux + // variables the evaluation point. + elemVars.saveScvfVars(); // calculate the local jacobian matrix - int numVertices = fvElemGeom_.numVertices; - ElementSolutionVector partialDeriv(numVertices); - PrimaryVariables storageDeriv; - for (int j = 0; j < numVertices; j++) { + int numScv = elemVars.numScv(); + for (int scvIdx = 0; scvIdx < numScv; scvIdx++) { for (int pvIdx = 0; pvIdx < numEq; pvIdx++) { - asImp_().evalPartialDerivative_(partialDeriv, - storageDeriv, - j, + asImp_().evalPartialDerivative_(elemVars, + scvIdx, pvIdx); - // update the local stiffness matrix with the current partial - // derivatives - updateLocalJacobian_(j, - pvIdx, - partialDeriv, - storageDeriv); + // update the local stiffness matrix with the current + // partial derivatives + updateLocalJacobian_(elemVars, scvIdx, pvIdx); } } - } - - /*! - * \brief Returns a reference to the object which calculates the - * local residual. - */ - const LocalResidual &localResidual() const - { return localResidual_; } - - /*! - * \brief Returns a reference to the object which calculates the - * local residual. - */ - LocalResidual &localResidual() - { return localResidual_; } - - /*! - * \brief Returns the Jacobian of the equations at vertex i to the - * primary variables at vertex j. - * - * \param i The local vertex (or sub-control volume) index on which - * the equations are defined - * \param j The local vertex (or sub-control volume) index which holds - * primary variables - */ - const MatrixBlock &mat(int i, int j) const - { return A_[i][j]; } - - /*! - * \brief Returns the Jacobian of the storage term at vertex i. - * - * \param i The local vertex (or sub-control volume) index - */ - const MatrixBlock &storageJacobian(int i) const - { return storageJacobian_[i]; } - - /*! - * \brief Returns the residual of the equations at vertex i. - * - * \param i The local vertex (or sub-control volume) index on which - * the equations are defined - */ - const PrimaryVariables &residual(int i) const - { return residual_[i]; } - /*! - * \brief Returns the storage term for vertex i. - * - * \param i The local vertex (or sub-control volume) index on which - * the equations are defined - */ - const PrimaryVariables &storageTerm(int i) const - { return storageTerm_[i]; } + // restore flux variables. + //elemVars.restoreScvfVars(); // not necessary + } /*! * \brief Returns the epsilon value which is added and removed @@ -281,7 +211,8 @@ public: * which the local derivative ought to be calculated. * \param pvIdx The index of the primary variable which gets varied */ - Scalar numericEpsilon(int scvIdx, + Scalar numericEpsilon(const ElementVariables &elemVars, + int scvIdx, int pvIdx) const { // define the base epsilon as the geometric mean of 1 and the @@ -291,71 +222,102 @@ public: static const Scalar baseEps = Dumux::geometricMean<Scalar>(std::numeric_limits<Scalar>::epsilon(), 1.0); - + // the epsilon value used for the numeric differentiation is // now scaled by the absolute value of the primary variable... - Scalar pv = this->curVolVars_[scvIdx].primaryVar(pvIdx); + Scalar pv = elemVars.volVars(scvIdx, /*historyIdx=*/0).primaryVar(pvIdx); return baseEps*(std::abs(pv) + 1); } -protected: - Implementation &asImp_() - { return *static_cast<Implementation*>(this); } - const Implementation &asImp_() const - { return *static_cast<const Implementation*>(this); } + /*! + * \brief Return reference to the local residual. + */ + LocalResidual &localResidual() + { return localResidual_; } + const LocalResidual &localResidual() const + { return localResidual_; } /*! - * \brief Returns a reference to the problem. + * \brief Returns the local Jacobian matrix of the residual of a sub-control volume. + * + * \param domainScvIdx The local index of the sub control volume which contains the independents + * \param rangeScvIdx The local index of the sub control volume which contains the local residual */ - const Problem &problem_() const - { - Valgrind::CheckDefined(problemPtr_); - return *problemPtr_; - }; + const MatrixBlock &jacobian(int domainScvIdx, int rangeScvIdx) const + { return jacobian_[domainScvIdx][rangeScvIdx]; } /*! - * \brief Returns a reference to the grid view. + * \brief Returns the local Jacobian matrix the storage term of a sub-control volume. + * + * \param scvIdx The local index of sub control volume */ - const GridView &gridView_() const - { return problem_().gridView(); } + const MatrixBlock &jacobianStorage(int scvIdx) const + { return jacobianStorage_[scvIdx]; } /*! - * \brief Returns a reference to the element. + * \brief Returns the local residual of a sub-control volume. + * + * \param scvIdx The local index of the sub control volume */ - const Element &elem_() const - { - Valgrind::CheckDefined(elemPtr_); - return *elemPtr_; - }; + const VectorBlock &residual(int scvIdx) const + { return residual_[scvIdx]; } /*! - * \brief Returns a reference to the model. + * \brief Returns the local storage term of a sub-control volume. + * + * \param scvIdx The local index of the sub control volume */ + const VectorBlock &residualStorage(int scvIdx) const + { return residualStorage_[scvIdx]; } + +protected: + Implementation &asImp_() + { return *static_cast<Implementation*>(this); } + const Implementation &asImp_() const + { return *static_cast<const Implementation*>(this); } + + const Problem &problem_() const + { return *problemPtr_; } const Model &model_() const - { return problem_().model(); }; + { return *modelPtr_; } /*! - * \brief Returns a reference to the jacobian assembler. + * \brief Returns the numeric difference method which is applied. */ - const JacobianAssembler &jacAsm_() const - { return model_().jacobianAssembler(); } + static int numericDifferenceMethod_() + { return GET_PARAM(TypeTag, int, NumericDifferenceMethod); } /*! - * \brief Returns a reference to the vertex mapper. + * \brief Resize all internal attributes to the size of the + * element. */ - const VertexMapper &vertexMapper_() const - { return problem_().vertexMapper(); }; + void resize_(const ElementVariables &elemVars) + { + int n = elemVars.numScv(); + + jacobian_.setSize(n, n); + jacobianStorage_.resize(n); + + residual_.resize(n); + residualStorage_.resize(n); + + derivResidual_.resize(n); + derivStorage_.resize(n); + }; /*! - * \brief Reset the local jacobian matrix to 0 + * \brief Reset the all relevant internal attributes to 0 */ - void reset_() + void reset_(const ElementVariables &elemVars) { - int n = elem_().template count<dim>(); - for (int i = 0; i < n; ++ i) { - storageJacobian_[i] = 0.0; - for (int j = 0; j < n; ++ j) { - A_[i][j] = 0.0; + int numScv = elemVars.numScv(); + for (int i = 0; i < numScv; ++ i) { + residual_[i] = 0.0; + residualStorage_[i] = 0.0; + + jacobianStorage_[i] = 0.0; + for (int j = 0; j < numScv; ++ j) { + jacobian_[i][j] = 0.0; } } } @@ -404,21 +366,19 @@ protected: * for which the partial derivative ought to be * calculated */ - void evalPartialDerivative_(ElementSolutionVector &dest, - PrimaryVariables &destStorage, + void evalPartialDerivative_(ElementVariables &elemVars, int scvIdx, int pvIdx) { - int globalIdx = vertexMapper_().map(elem_(), scvIdx, dim); - - PrimaryVariables priVars(model_().curSol()[globalIdx]); - VolumeVariables origVolVars(curVolVars_[scvIdx]); + // save all quantities which depend on the specified primary + // variable at the given sub control volume + elemVars.saveScvVars(scvIdx); - curVolVars_[scvIdx].setEvalPoint(&origVolVars); - Scalar eps = asImp_().numericEpsilon(scvIdx, pvIdx); + PrimaryVariables priVars(elemVars.volVars(scvIdx, /*historyIdx=*/0).primaryVars()); + Scalar eps = asImp_().numericEpsilon(elemVars, scvIdx, pvIdx); Scalar delta = 0; - if (numericDifferenceMethod_ >= 0) { + if (numericDifferenceMethod_() >= 0) { // we are not using backward differences, i.e. we need to // calculate f(x + \epsilon) @@ -427,32 +387,19 @@ protected: delta += eps; // calculate the residual - curVolVars_[scvIdx].update(priVars, - problem_(), - elem_(), - fvElemGeom_, - scvIdx, - false); - localResidual().eval(elem_(), - fvElemGeom_, - prevVolVars_, - curVolVars_, - bcTypes_); - - // store the residual and the storage term - dest = localResidual().residual(); - destStorage = localResidual().storageTerm()[scvIdx]; + elemVars.updateScvVars(priVars, scvIdx, /*historyIdx=*/0); + elemVars.updateAllScvfVars(); + localResidual_.eval(derivResidual_, derivStorage_, elemVars); } else { // we are using backward differences, i.e. we don't need // to calculate f(x + \epsilon) and we can recycle the // (already calculated) residual f(x) - dest = residual_; - destStorage = storageTerm_[scvIdx]; + derivResidual_ = residual_; + derivStorage_[scvIdx] = residualStorage_[scvIdx]; } - - if (numericDifferenceMethod_ <= 0) { + if (numericDifferenceMethod_() <= 0) { // we are not using forward differences, i.e. we don't // need to calculate f(x - \epsilon) @@ -460,40 +407,35 @@ protected: priVars[pvIdx] -= delta + eps; delta += eps; - // calculate residual again - curVolVars_[scvIdx].update(priVars, - problem_(), - elem_(), - fvElemGeom_, - scvIdx, - false); - localResidual().eval(elem_(), - fvElemGeom_, - prevVolVars_, - curVolVars_, - bcTypes_); - dest -= localResidual().residual(); - destStorage -= localResidual().storageTerm()[scvIdx]; + // calculate residual again, this time we use the local + // residual's internal storage. + elemVars.updateScvVars(priVars, scvIdx, /*historyIdx=*/0); + elemVars.updateAllScvfVars(); + localResidual_.eval(elemVars); + + derivResidual_ -= localResidual_.residual(); + derivStorage_[scvIdx] -= localResidual_.storageTerm()[scvIdx]; } else { // we are using forward differences, i.e. we don't need to // calculate f(x - \epsilon) and we can recycle the // (already calculated) residual f(x) - dest -= residual_; - destStorage -= storageTerm_[scvIdx]; + derivResidual_ -= residual_; + derivStorage_[scvIdx] -= residualStorage_[scvIdx]; } // divide difference in residuals by the magnitude of the // deflections between the two function evaluation - dest /= delta; - destStorage /= delta; + derivResidual_ /= delta; + derivStorage_[scvIdx] /= delta; - // restore the original state of the element's volume variables - curVolVars_[scvIdx] = origVolVars; + // restore the original state of the element's volume + // variables + elemVars.restoreScvVars(scvIdx); -#if HAVE_VALGRIND - for (unsigned i = 0; i < dest.size(); ++i) - Valgrind::CheckDefined(dest[i]); +#ifndef NDEBUG + for (unsigned i = 0; i < derivResidual_.size(); ++i) + Valgrind::CheckDefined(derivResidual_[i]); #endif } @@ -502,56 +444,44 @@ protected: * partial derivatives of all equations in regard to the * primary variable 'pvIdx' at vertex 'scvIdx' . */ - void updateLocalJacobian_(int scvIdx, - int pvIdx, - const ElementSolutionVector &deriv, - const PrimaryVariables &storageDeriv) + void updateLocalJacobian_(const ElementVariables &elemVars, + int scvIdx, + int pvIdx) { // store the derivative of the storage term for (int eqIdx = 0; eqIdx < numEq; eqIdx++) { - storageJacobian_[scvIdx][eqIdx][pvIdx] = storageDeriv[eqIdx]; + jacobianStorage_[scvIdx][eqIdx][pvIdx] = derivStorage_[scvIdx][eqIdx]; } - for (int i = 0; i < fvElemGeom_.numVertices; i++) + int numScv = elemVars.numScv(); + for (int eqScvIdx = 0; eqScvIdx < numScv; eqScvIdx++) { - if (jacAsm_().vertexColor(elem_(), i) == Green) { - // Green vertices are not to be changed! - continue; - } - for (int eqIdx = 0; eqIdx < numEq; eqIdx++) { - // A[i][scvIdx][eqIdx][pvIdx] is the rate of change of - // the residual of equation 'eqIdx' at vertex 'i' - // depending on the primary variable 'pvIdx' at vertex - // 'scvIdx'. - this->A_[i][scvIdx][eqIdx][pvIdx] = deriv[i][eqIdx]; - Valgrind::CheckDefined(this->A_[i][scvIdx][eqIdx][pvIdx]); + // A[eqScvIdx][scvIdx][eqIdx][pvIdx] is the rate of + // change of the residual of equation 'eqIdx' at + // vertex 'eqScvIdx' depending on the primary variable + // 'pvIdx' at vertex 'scvIdx'. + jacobian_[eqScvIdx][scvIdx][eqIdx][pvIdx] = derivResidual_[eqScvIdx][eqIdx]; + Valgrind::CheckDefined(jacobian_[eqScvIdx][scvIdx][eqIdx][pvIdx]); } } } - const Element *elemPtr_; - FVElementGeometry fvElemGeom_; - - ElementBoundaryTypes bcTypes_; - - // The problem we would like to solve Problem *problemPtr_; + Model *modelPtr_; - // secondary variables at the previous and at the current time - // levels - ElementVolumeVariables prevVolVars_; - ElementVolumeVariables curVolVars_; + ElementVariables *internalElemVars_; - LocalResidual localResidual_; + LocalBlockMatrix jacobian_; + LocalStorageMatrix jacobianStorage_; - LocalBlockMatrix A_; - std::vector<MatrixBlock> storageJacobian_; + LocalBlockVector residual_; + LocalBlockVector residualStorage_; - ElementSolutionVector residual_; - ElementSolutionVector storageTerm_; + LocalBlockVector derivResidual_; + LocalBlockVector derivStorage_; - int numericDifferenceMethod_; + LocalResidual localResidual_; }; } diff --git a/dumux/boxmodels/common/boxlocalresidual.hh b/dumux/boxmodels/common/boxlocalresidual.hh index d22a826c8fa3dc6143c212761b96aac1e6918a3c..b3176627521054f4dd00e5e3a041a1efc27dda12 100644 --- a/dumux/boxmodels/common/boxlocalresidual.hh +++ b/dumux/boxmodels/common/boxlocalresidual.hh @@ -25,7 +25,7 @@ #ifndef DUMUX_BOX_LOCAL_RESIDUAL_HH #define DUMUX_BOX_LOCAL_RESIDUAL_HH -#include <dune/istl/matrix.hh> +#include <dune/istl/bvector.hh> #include <dune/grid/common/geometry.hh> #include <dumux/common/valgrind.hh> @@ -47,48 +47,33 @@ class BoxLocalResidual private: typedef BoxLocalResidual<TypeTag> ThisType; typedef typename GET_PROP_TYPE(TypeTag, PTAG(LocalResidual)) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(Problem)) Problem; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(Model)) Model; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(GridView)) GridView; - - enum { - numEq = GET_PROP_VALUE(TypeTag, PTAG(NumEq)), - - dim = GridView::dimension, - dimWorld = GridView::dimensionworld - }; - - typedef typename GET_PROP_TYPE(TypeTag, PTAG(Scalar)) Scalar; - typedef typename GridView::Grid::ctype CoordScalar; - - typedef Dune::FieldVector<Scalar, dim> LocalPosition; - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(GridView)) GridView; + 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>::Entity Vertex; typedef typename GridView::template Codim<dim>::EntityPointer VertexPointer; + typedef typename GridView::ctype CoordScalar; typedef typename Dune::GenericReferenceElements<CoordScalar, dim> ReferenceElements; typedef typename Dune::GenericReferenceElement<CoordScalar, dim> ReferenceElement; + typedef typename GridView::Intersection Intersection; typedef typename GridView::IntersectionIterator IntersectionIterator; typedef typename Element::Geometry Geometry; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(FVElementGeometry)) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(VertexMapper)) VertexMapper; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementSolutionVector)) ElementSolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVariables)) ElementVariables; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(Scalar)) Scalar; typedef typename GET_PROP_TYPE(TypeTag, PTAG(PrimaryVariables)) PrimaryVariables; typedef typename GET_PROP_TYPE(TypeTag, PTAG(BoundaryTypes)) BoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementBoundaryTypes)) ElementBoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(VolumeVariables)) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVolumeVariables)) ElementVolumeVariables; - - typedef Dune::FieldMatrix<Scalar, numEq, numEq> MatrixBlock; - typedef Dune::Matrix<MatrixBlock> LocalBlockMatrix; + enum { numEq = GET_PROP_VALUE(TypeTag, PTAG(NumEq)) }; + typedef Dune::FieldVector<Scalar, numEq> VectorBlock; + typedef Dune::BlockVector<VectorBlock> LocalBlockVector; + // copying the local residual class is not a good idea - BoxLocalResidual(const BoxLocalResidual &); + BoxLocalResidual(const BoxLocalResidual &) + {}; public: BoxLocalResidual() @@ -97,312 +82,217 @@ public: ~BoxLocalResidual() { } - /*! - * \brief Initialize the local residual. - * - * This assumes that all objects of the simulation have been fully - * allocated but not necessarrily initialized completely. - * - * \param prob The representation of the physical problem to be - * solved. - */ - void init(Problem &prob) - { problemPtr_ = &prob; } - /*! * \brief Compute the local residual, i.e. the deviation of the - * equations from zero. + * conservation equations from zero and store the results + * internally. * - * \param element The DUNE Codim<0> entity for which the residual - * ought to be calculated + * The results can be requested afterwards using the residual() + * and storageTerm() methods. */ - void eval(const Element &element) + void eval(const ElementVariables &elemVars) { - FVElementGeometry fvElemGeom; - - fvElemGeom.update(gridView_(), element); - fvElemGeomPtr_ = &fvElemGeom; - - ElementVolumeVariables volVarsPrev, volVarsCur; - // update the hints - model_().setHints(element, volVarsPrev, volVarsCur); - - volVarsPrev.update(problem_(), - element, - fvElemGeom_(), - true /* oldSol? */); - volVarsCur.update(problem_(), - element, - fvElemGeom_(), - false /* oldSol? */); - - ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvElemGeom_()); - - // this is pretty much a HACK because the internal state of - // the problem is not supposed to be changed during the - // evaluation of the residual. (Reasons: It is a violation of - // abstraction, makes everything more prone to errors and is - // not thread save.) The real solution are context objects! - problem_().updateCouplingParams(element); - - asImp_().eval(element, fvElemGeom_(), volVarsPrev, volVarsCur, bcTypes); - } + int numScv = elemVars.numScv(); + internalResidual_.resize(numScv); + internalStorageTerm_.resize(numScv); + eval(internalResidual_, internalStorageTerm_, elemVars); + }; + /*! - * \brief Compute the local residual, i.e. the deviation of the - * equations from zero. Gets a solution vector computed by PDELab - * - * \param element The DUNE Codim<0> entity for which the residual - * ought to be calculated - * \param elementSolVector The local solution for the element using PDELab ordering + * \brief Return the result of the eval() call using internal + * storage. */ - template<typename ElemSolVectorType> - void evalPDELab(const Element &element, const ElemSolVectorType& elementSolVector) - { - FVElementGeometry fvGeom; - fvGeom.update(gridView_(), element); - ElementVolumeVariables volVarsPrev, volVarsCur; - volVarsPrev.update(problem_(), - element, - fvGeom, - true /* oldSol? */); - volVarsCur.updatePDELab(problem_(), - element, - fvGeom, - elementSolVector); - ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvGeom); - - // this is pretty much a HACK because the internal state of - // the problem is not supposed to be changed during the - // evaluation of the residual. (Reasons: It is a violation of - // abstraction, makes everything more prone to errors and is - // not thread save.) The real solution are context objects! - problem_().updateCouplingParams(element); - - asImp_().eval(element, fvGeom, volVarsPrev, volVarsCur, bcTypes); - } + const LocalBlockVector &residual() const + { return internalResidual_; } + const VectorBlock &residual(int scvIdx) const + { return internalResidual_[scvIdx]; } /*! - * \brief Compute the storage term for the current solution. - * - * This can be used to figure out how much of each conservation - * quantity is inside the element. - * - * \param element The DUNE Codim<0> entity for which the storage - * term ought to be calculated + * \brief Return the storage term calculated using the last call + * to eval() using internal storage. */ - void evalStorage(const Element &element) - { - elemPtr_ = &element; - - FVElementGeometry fvElemGeom; - fvElemGeom.update(gridView_(), element); - fvElemGeomPtr_ = &fvElemGeom; - - ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvElemGeom_()); - bcTypesPtr_ = &bcTypes; - - // no previous volume variables! - prevVolVarsPtr_ = 0; - - ElementVolumeVariables volVars; - - // update the hints - model_().setHints(element, volVars); - - // calculate volume current variables - volVars.update(problem_(), element, fvElemGeom_(), false); - curVolVarsPtr_ = &volVars; - - asImp_().evalStorage_(); - } - - /*! - * \brief Compute the flux term for the current solution. - * - * \param element The DUNE Codim<0> entity for which the residual - * ought to be calculated - * \param curVolVars The volume averaged variables for all - * sub-contol volumes of the element - */ - void evalFluxes(const Element &element, - const ElementVolumeVariables &curVolVars) - { - elemPtr_ = &element; - - FVElementGeometry fvElemGeom; - fvElemGeom.update(gridView_(), element); - fvElemGeomPtr_ = &fvElemGeom; - - ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvElemGeom_()); - - residual_.resize(fvElemGeom_().numVertices); - residual_ = 0; - - bcTypesPtr_ = &bcTypes; - prevVolVarsPtr_ = 0; - curVolVarsPtr_ = &curVolVars; - asImp_().evalFluxes_(); - } - + const LocalBlockVector &storageTerm() const + { return internalStorageTerm_; } + const VectorBlock &storageTerm(int scvIdx) const + { return internalStorageTerm_[scvIdx]; } + /*! * \brief Compute the local residual, i.e. the deviation of the - * equations from zero. + * conservation equations from zero. * - * \param element The DUNE Codim<0> entity for which the residual - * ought to be calculated - * \param fvGeom The finite-volume geometry of the element - * \param prevVolVars The volume averaged variables for all - * sub-contol volumes of the element at the previous - * time level - * \param curVolVars The volume averaged variables for all - * sub-contol volumes of the element at the current - * time level - * \param bcTypes The types of the boundary conditions for all - * vertices of the element + * \param residual Stores the residual vector + * \param storageTerm Stores the derivative of the storage term to time + * \param elemVars All the element's secondary variables required to calculate the local residual */ - void eval(const Element &element, - const FVElementGeometry &fvGeom, - const ElementVolumeVariables &prevVolVars, - const ElementVolumeVariables &curVolVars, - const ElementBoundaryTypes &bcTypes) + void eval(LocalBlockVector &residual, + LocalBlockVector &storageTerm, + const ElementVariables &elemVars) const { - //Valgrind::CheckDefined(fvGeom); - Valgrind::CheckDefined(prevVolVars); - Valgrind::CheckDefined(curVolVars); + residual = 0.0; + storageTerm = 0.0; -#if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvGeom.numVertices; i++) { - prevVolVars[i].checkDefined(); - curVolVars[i].checkDefined(); - } -#endif // HAVE_VALGRIND - - elemPtr_ = &element; - fvElemGeomPtr_ = &fvGeom; - bcTypesPtr_ = &bcTypes; - prevVolVarsPtr_ = &prevVolVars; - curVolVarsPtr_ = &curVolVars; - - // resize the vectors for all terms - int numVerts = fvElemGeom_().numVertices; - residual_.resize(numVerts); - storageTerm_.resize(numVerts); - - residual_ = 0.0; - storageTerm_ = 0.0; - - asImp_().evalFluxes_(); + // evaluate the flux terms + asImp_().evalFluxes(residual, elemVars); #if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvElemGeom_().numVertices; i++) - Valgrind::CheckDefined(residual_[i]); + for (int i=0; i < elemVars.fvElemGeom().numVertices; i++) + Valgrind::CheckDefined(residual[i]); #endif // HAVE_VALGRIND - asImp_().evalVolumeTerms_(); + // evaluate the storage and the source terms + asImp_().evalVolumeTerms_(residual, storageTerm, elemVars); #if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvElemGeom_().numVertices; i++) { - Valgrind::CheckDefined(residual_[i]); - } -#endif // HAVE_VALGRIND + for (int i=0; i < elemVars.fvElemGeom().numVertices; i++) + Valgrind::CheckDefined(residual[i]); +#endif // !defined NDEBUG && HAVE_VALGRIND // evaluate the boundary conditions - asImp_().evalBoundary_(); + asImp_().evalBoundary_(residual, storageTerm, elemVars); #if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvElemGeom_().numVertices; i++) - Valgrind::CheckDefined(residual_[i]); + for (int i=0; i < elemVars.fvElemGeom().numVertices; i++) + Valgrind::CheckDefined(residual[i]); #endif // HAVE_VALGRIND } /*! - * \brief Returns the local residual for a given sub-control - * volume of the element. + * \brief Calculate the amount of all conservation quantities + * stored in all element's sub-control volumes for a given + * history index. + * + * This is used to figure out how much of each conservation + * quantity is inside the element. */ - const ElementSolutionVector &residual() const - { return residual_; } + void evalStorage(const ElementVariables &elemVars, + int historyIdx) + { + int numScv = elemVars.numScv(); + internalStorageTerm_.resize(numScv); + evalStorage(internalStorageTerm_, + elemVars, + historyIdx); + } /*! - * \brief Returns the local residual for a given sub-control - * volume of the element. + * \brief Calculate the amount of all conservation quantities + * stored in all element's sub-control volumes for a given + * history index. * - * \param scvIdx The local index of the sub-control volume - * (i.e. the element's local vertex index) + * This is used to figure out how much of each conservation + * quantity is inside the element. */ - const PrimaryVariables &residual(int scvIdx) const - { return residual_[scvIdx]; } + void evalStorage(LocalBlockVector &storage, + const ElementVariables &elemVars, + int historyIdx) const + { + // calculate the amount of conservation each quantity inside + // all sub control volumes + for (int scvIdx=0; scvIdx < elemVars.numScv(); scvIdx++) + { + storage[scvIdx] = 0.0; + asImp_().computeStorage(storage[scvIdx], + elemVars, + scvIdx, + historyIdx); + storage[scvIdx] *= + elemVars.fvElemGeom().subContVol[scvIdx].volume + * elemVars.volVars(scvIdx).extrusionFactor(); + } + } /*! - * \brief Returns the storage term for all sub-control volumes of the - * element. + * \brief Add the flux term to a local residual. */ - const ElementSolutionVector &storageTerm() const - { return storageTerm_; } - -protected: - Implementation &asImp_() + void evalFluxes(LocalBlockVector &residual, + const ElementVariables &elemVars) const { - assert(static_cast<Implementation*>(this) != 0); - return *static_cast<Implementation*>(this); - } + PrimaryVariables flux; + + // calculate the mass flux over the sub-control volume faces + for (int scvfIdx = 0; + scvfIdx < elemVars.fvElemGeom().numEdges; + scvfIdx++) + { + int i = elemVars.fvElemGeom().subContVolFace[scvfIdx].i; + int j = elemVars.fvElemGeom().subContVolFace[scvfIdx].j; - const Implementation &asImp_() const - { - assert(static_cast<const Implementation*>(this) != 0); - return *static_cast<const Implementation*>(this); + Valgrind::SetUndefined(flux); + asImp_().computeFlux(flux, /*context=*/elemVars, scvfIdx); + flux *= elemVars.fluxVars(scvfIdx).extrusionFactor(); + Valgrind::CheckDefined(flux); + + // The balance equation for a finite volume is given by + // + // dStorage/dt = Flux + Source + // + // where the 'Flux' and the 'Source' terms represent the + // mass per second which _ENTER_ the finite + // volume. Re-arranging this, we get + // + // dStorage/dt - Source - Flux = 0 + // + // Since the mass flux as calculated by computeFlux() goes + // _OUT_ of sub-control volume i and _INTO_ sub-control + // volume j, we need to add the flux to finite volume i + // and subtract it from finite volume j + residual[i] += flux; + residual[j] -= flux; + } } +protected: /*! - * \brief Evaluate the boundary conditions - * of the current element. + * \brief Evaluate the boundary conditions of an element. */ - void evalBoundary_() + void evalBoundary_(LocalBlockVector &residual, + LocalBlockVector &storageTerm, + const ElementVariables &elemVars) const { - if (bcTypes_().hasNeumann()) - asImp_().evalNeumann_(); -#if !defined NDEBUG && HAVE_VALGRIND - for (int i=0; i < fvElemGeom_().numVertices; i++) - Valgrind::CheckDefined(residual_[i]); -#endif // HAVE_VALGRIND - - if (bcTypes_().hasDirichlet()) - asImp_().evalDirichlet_(); + if (!elemVars.onBoundary()) { + return; + } + + if (elemVars.hasNeumann()) + asImp_().evalNeumann_(residual, elemVars); + + if (elemVars.hasDirichlet()) + asImp_().evalDirichlet_(residual, storageTerm, elemVars); } /*! * \brief Set the values of the Dirichlet boundary control volumes * of the current element. */ - void evalDirichlet_() + void evalDirichlet_(LocalBlockVector &residual, + LocalBlockVector &storageTerm, + const ElementVariables &elemVars) const { PrimaryVariables tmp(0); - for (int i = 0; i < fvElemGeom_().numVertices; ++i) { - const BoundaryTypes &bcTypes = bcTypes_(i); - if (! bcTypes.hasDirichlet()) + for (int scvIdx = 0; scvIdx < elemVars.numScv(); ++scvIdx) { + const BoundaryTypes &bcTypes = elemVars.boundaryTypes(scvIdx); + if (!bcTypes.hasDirichlet()) continue; - + // ask the problem for the dirichlet values - const VertexPointer vPtr = elem_().template subEntity<dim>(i); - asImp_().problem_().dirichlet(tmp, *vPtr); + asImp_().computeDirichlet_(tmp, elemVars, scvIdx); + + const PrimaryVariables &priVars = + elemVars.volVars(scvIdx).primaryVars(); // set the dirichlet conditions for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { if (!bcTypes.isDirichlet(eqIdx)) continue; int pvIdx = bcTypes.eqToDirichletIndex(eqIdx); + assert(0 <= pvIdx && pvIdx < numEq); Valgrind::CheckDefined(pvIdx); - Valgrind::CheckDefined(curPrimaryVar_(i, pvIdx)); + Valgrind::CheckDefined(priVars); Valgrind::CheckDefined(tmp[pvIdx]); - this->residual_[i][eqIdx] = - curPrimaryVar_(i, pvIdx) - tmp[pvIdx]; - - this->storageTerm_[i][eqIdx] = 0.0; + residual[scvIdx][eqIdx] = priVars[pvIdx] - tmp[pvIdx]; + storageTerm[scvIdx][eqIdx] = 0.0; }; }; } @@ -411,13 +301,16 @@ protected: * \brief Add all Neumann boundary conditions to the local * residual. */ - void evalNeumann_() + void evalNeumann_(LocalBlockVector &residual, + const ElementVariables &elemVars) const { - Dune::GeometryType geoType = elem_().geometry().type(); + const Element &elem = elemVars.element(); + Dune::GeometryType geoType = elem.geometry().type(); const ReferenceElement &refElem = ReferenceElements::general(geoType); - IntersectionIterator isIt = gridView_().ibegin(elem_()); - const IntersectionIterator &endIt = gridView_().iend(elem_()); + const GridView &gridView = elemVars.gridView(); + IntersectionIterator isIt = gridView.ibegin(elem); + const IntersectionIterator &endIt = gridView.iend(elem); for (; isIt != endIt; ++isIt) { // handle only faces on the boundary @@ -432,112 +325,59 @@ protected: faceVertIdx < numFaceVerts; ++faceVertIdx) { - int elemVertIdx = refElem.subEntity(faceIdx, - 1, - faceVertIdx, - dim); - + int scvIdx = refElem.subEntity(/*entityIdx=*/faceIdx, + /*entityCodim=*/1, + /*subEntityIdx=*/faceVertIdx, + /*subEntityCodim=*/dim); + int boundaryFaceIdx = - fvElemGeom_().boundaryFaceIndex(faceIdx, faceVertIdx); + elemVars.fvElemGeom().boundaryFaceIndex(faceIdx, faceVertIdx); // add the residual of all vertices of the boundary // segment - evalNeumannSegment_(isIt, - elemVertIdx, + evalNeumannSegment_(residual, + elemVars, + *isIt, + scvIdx, boundaryFaceIdx); } } } + void computeDirichlet_(PrimaryVariables &values, + const ElementVariables &elemVars, + int scvIdx) const + { elemVars.problem().dirichlet(values, elemVars, scvIdx); } + + /*! * \brief Add Neumann boundary conditions for a single sub-control * volume face to the local residual. */ - void evalNeumannSegment_(const IntersectionIterator &isIt, + void evalNeumannSegment_(LocalBlockVector &residual, + const ElementVariables &elemVars, + const Intersection &is, int scvIdx, - int boundaryFaceIdx) + int boundaryFaceIdx) const { // temporary vector to store the neumann boundary fluxes - PrimaryVariables values(0.0); - const BoundaryTypes &bcTypes = bcTypes_(scvIdx); - + const BoundaryTypes &bcTypes = elemVars.boundaryTypes(scvIdx); + PrimaryVariables values; + // deal with neumann boundaries if (bcTypes.hasNeumann()) { - problem_().boxSDNeumann(values, - elem_(), - fvElemGeom_(), - *isIt, - scvIdx, - boundaryFaceIdx, - curVolVars_()); - if (!Valgrind::CheckDefined(values)) - std::cerr << "undefined: " << values << "\n"; - values *= - fvElemGeom_().boundaryFace[boundaryFaceIdx].area - * curVolVars_(scvIdx).extrusionFactor(); + elemVars.problem().neumann(values, + elemVars, + is, + scvIdx, + boundaryFaceIdx); Valgrind::CheckDefined(values); - residual_[scvIdx] += values; - } - } - - /*! - * \brief Add the flux terms to the local residual of all - * sub-control volumes of the current element. - */ - void evalFluxes_() - { - // calculate the mass flux over the faces and subtract - // it from the local rates - for (int k = 0; k < fvElemGeom_().numEdges; k++) - { - int i = fvElemGeom_().subContVolFace[k].i; - int j = fvElemGeom_().subContVolFace[k].j; - PrimaryVariables flux; - Valgrind::SetUndefined(flux); - this->asImp_().computeFlux(flux, k); - Scalar extrusionFactor = - (curVolVars_(i).extrusionFactor() - + curVolVars_(j).extrusionFactor()) - / 2; - flux *= extrusionFactor; - Valgrind::CheckDefined(flux); - - // The balance equation for a finite volume is: - // - // dStorage/dt = Flux + Source - // - // where the 'Flux' and the 'Source' terms represent the - // mass per second which _ENTER_ the finite - // volume. Re-arranging this, we get - // - // dStorage/dt - Source - Flux = 0 - // - // Since the flux calculated by computeFlux() goes _OUT_ - // of sub-control volume i and _INTO_ sub-control volume - // j, we need to add the flux to finite volume i and - // subtract it from finite volume j - residual_[i] += flux; - residual_[j] -= flux; - } - } - - /*! - * \brief Set the local residual to the storage terms of all - * sub-control volumes of the current element. - */ - void evalStorage_() - { - storageTerm_.resize(fvElemGeom_().numVertices); - storageTerm_ = 0; - - // calculate the amount of conservation each quantity inside - // all sub control volumes - for (int i=0; i < fvElemGeom_().numVertices; i++) { - this->asImp_().computeStorage(storageTerm_[i], i, /*isOldSol=*/false); - storageTerm_[i] *= - fvElemGeom_().subContVol[i].volume - * curVolVars_(i).extrusionFactor(); + values *= + elemVars.fvElemGeom().boundaryFace[boundaryFaceIdx].area + * elemVars.volVars(scvIdx, /*historyIdx*/0).extrusionFactor(); + Valgrind::CheckDefined(values); + residual[scvIdx] += values; } } @@ -546,15 +386,17 @@ protected: * to the local residual of all sub-control volumes of the * current element. */ - void evalVolumeTerms_() + void evalVolumeTerms_(LocalBlockVector &residual, + LocalBlockVector &storageTerm, + const ElementVariables &elemVars) const { + PrimaryVariables tmp, tmp2; + // evaluate the volume terms (storage + source terms) - for (int i=0; i < fvElemGeom_().numVertices; i++) + for (int scvIdx=0; scvIdx < elemVars.numScv(); scvIdx++) { Scalar extrusionFactor = - curVolVars_(i).extrusionFactor(); - - PrimaryVariables tmp(0); + elemVars.volVars(scvIdx, /*historyIdx=*/0).extrusionFactor(); // mass balance within the element. this is the // $\frac{m}{\partial t}$ term if using implicit @@ -562,162 +404,51 @@ protected: // // TODO (?): we might need a more explicit way for // doing the time discretization... - this->asImp_().computeStorage(storageTerm_[i], i, false); - this->asImp_().computeStorage(tmp, i, true); + asImp_().computeStorage(tmp2, + elemVars, + scvIdx, + /*historyIdx=*/1); + asImp_().computeStorage(tmp, + elemVars, + scvIdx, + /*historyIdx=*/0); - storageTerm_[i] -= tmp; - storageTerm_[i] *= - fvElemGeom_().subContVol[i].volume - / problem_().timeManager().timeStepSize() + tmp -= tmp2; + tmp *= + elemVars.fvElemGeom().subContVol[scvIdx].volume + / elemVars.problem().timeManager().timeStepSize() * extrusionFactor; - residual_[i] += storageTerm_[i]; - // subtract the source term from the local rate - this->asImp_().computeSource(tmp, i); - tmp *= fvElemGeom_().subContVol[i].volume * extrusionFactor; - residual_[i] -= tmp; + storageTerm[scvIdx] += tmp; + residual[scvIdx] += tmp; + + // subtract the source term from the residual + asImp_().computeSource(tmp2, elemVars, scvIdx); + tmp2 *= elemVars.fvElemGeom().subContVol[scvIdx].volume * extrusionFactor; + residual[scvIdx] -= tmp2; // make sure that only defined quantities were used // to calculate the residual. - Valgrind::CheckDefined(residual_[i]); + Valgrind::CheckDefined(storageTerm[scvIdx]); + Valgrind::CheckDefined(residual[scvIdx]); } } - /*! - * \brief Returns a reference to the problem. - */ - const Problem &problem_() const - { return *problemPtr_; }; - - /*! - * \brief Returns a reference to the model. - */ - const Model &model_() const - { return problem_().model(); }; - - /*! - * \brief Returns a reference to the vertex mapper. - */ - const VertexMapper &vertexMapper_() const - { return problem_().vertexMapper(); }; - - /*! - * \brief Returns a reference to the grid view. - */ - const GridView &gridView_() const - { return problem_().gridView(); } - - /*! - * \brief Returns a reference to the current element. - */ - const Element &elem_() const - { - Valgrind::CheckDefined(elemPtr_); - return *elemPtr_; - } - - /*! - * \brief Returns a reference to the current element's finite - * volume geometry. - */ - const FVElementGeometry &fvElemGeom_() const - { - Valgrind::CheckDefined(fvElemGeomPtr_); - return *fvElemGeomPtr_; - } - - /*! - * \brief Returns a reference to the primary variables of the i'th - * sub-control volume of the current element. - */ - const PrimaryVariables &curPrimaryVars_(int i) const - { - return curVolVars_(i).primaryVars(); - } - - /*! - * \brief Returns the j'th primary of the i'th sub-control volume - * of the current element. - */ - Scalar curPrimaryVar_(int i, int j) const - { - return curVolVars_(i).primaryVar(j); - } - - /*! - * \brief Returns a reference to the current volume variables of - * all sub-control volumes of the current element. - */ - const ElementVolumeVariables &curVolVars_() const - { - Valgrind::CheckDefined(curVolVarsPtr_); - return *curVolVarsPtr_; - } - - /*! - * \brief Returns a reference to the volume variables of the i-th - * sub-control volume of the current element. - */ - const VolumeVariables &curVolVars_(int i) const - { - return curVolVars_()[i]; - } - - /*! - * \brief Returns a reference to the previous time step's volume - * variables of all sub-control volumes of the current - * element. - */ - const ElementVolumeVariables &prevVolVars_() const - { - Valgrind::CheckDefined(prevVolVarsPtr_); - return *prevVolVarsPtr_; - } - - /*! - * \brief Returns a reference to the previous time step's volume - * variables of the i-th sub-control volume of the current - * element. - */ - const VolumeVariables &prevVolVars_(int i) const - { - return prevVolVars_()[i]; - } - - /*! - * \brief Returns a reference to the boundary types of all - * sub-control volumes of the current element. - */ - const ElementBoundaryTypes &bcTypes_() const +private: + Implementation &asImp_() { - Valgrind::CheckDefined(bcTypesPtr_); - return *bcTypesPtr_; + assert(static_cast<Implementation*>(this) != 0); + return *static_cast<Implementation*>(this); } - /*! - * \brief Returns a reference to the boundary types of the i-th - * sub-control volume of the current element. - */ - const BoundaryTypes &bcTypes_(int i) const + const Implementation &asImp_() const { - return bcTypes_()[i]; + assert(static_cast<const Implementation*>(this) != 0); + return *static_cast<const Implementation*>(this); } -protected: - ElementSolutionVector storageTerm_; - ElementSolutionVector residual_; - - // The problem we would like to solve - Problem *problemPtr_; - - const Element *elemPtr_; - const FVElementGeometry *fvElemGeomPtr_; - - // current and previous secondary variables for the element - const ElementVolumeVariables *prevVolVarsPtr_; - const ElementVolumeVariables *curVolVarsPtr_; - - const ElementBoundaryTypes *bcTypesPtr_; + LocalBlockVector internalResidual_; + LocalBlockVector internalStorageTerm_; }; } diff --git a/dumux/boxmodels/common/boxmodel.hh b/dumux/boxmodels/common/boxmodel.hh index 63625996a3a98be237fab81f12b0bb6749bf8f40..bfc52156f2a649e628d9a8a89b6d155a824bfb66 100644 --- a/dumux/boxmodels/common/boxmodel.hh +++ b/dumux/boxmodels/common/boxmodel.hh @@ -72,16 +72,18 @@ class BoxModel typedef typename GET_PROP_TYPE(TypeTag, PTAG(PrimaryVariables)) PrimaryVariables; typedef typename GET_PROP_TYPE(TypeTag, PTAG(JacobianAssembler)) JacobianAssembler; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVolumeVariables)) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVariables)) ElementVariables; typedef typename GET_PROP_TYPE(TypeTag, PTAG(VolumeVariables)) VolumeVariables; enum { numEq = GET_PROP_VALUE(TypeTag, PTAG(NumEq)), + historySize = GET_PROP_VALUE(TypeTag, PTAG(TimeDiscHistorySize)), dim = GridView::dimension }; typedef typename GET_PROP_TYPE(TypeTag, PTAG(FVElementGeometry)) FVElementGeometry; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(BoundaryTypes)) BoundaryTypes; typedef typename GET_PROP_TYPE(TypeTag, PTAG(LocalJacobian)) LocalJacobian; typedef typename GET_PROP_TYPE(TypeTag, PTAG(LocalResidual)) LocalResidual; @@ -93,6 +95,7 @@ class BoxModel typedef typename GridView::template Codim<0>::Iterator ElementIterator; typedef typename GridView::IntersectionIterator IntersectionIterator; typedef typename GridView::template Codim<dim>::Entity Vertex; + typedef typename GridView::template Codim<dim>::EntityPointer VertexPointer; typedef typename GridView::template Codim<dim>::Iterator VertexIterator; typedef typename Dune::GenericReferenceElements<CoordScalar, dim> ReferenceElements; @@ -106,9 +109,7 @@ public: * \brief The constructor. */ BoxModel() - { - enableHints_ = GET_PARAM(TypeTag, bool, EnableHints); - } + { } ~BoxModel() { delete jacAsm_; } @@ -123,9 +124,11 @@ public: { problemPtr_ = &prob; + updateBoundaryTypes_(); + int nDofs = asImp_().numDofs(); - uCur_.resize(nDofs); - uPrev_.resize(nDofs); + for (int historyIdx = 0; historyIdx < historySize; ++historyIdx) + solution_[historyIdx].resize(nDofs); boxVolume_.resize(nDofs); localJacobian_.init(problem_()); @@ -135,10 +138,10 @@ public: asImp_().applyInitialSolution_(); // resize the hint vectors - if (enableHints_) { + if (enableHints_()) { int nVerts = gridView_().size(dim); - curHints_.resize(nVerts); - prevHints_.resize(nVerts); + for (int historyIdx = 0; historyIdx < historySize; ++historyIdx) + hints_[historyIdx].resize(nVerts); hintsUsable_.resize(nVerts); std::fill(hintsUsable_.begin(), hintsUsable_.end(), @@ -147,74 +150,67 @@ public: // also set the solution of the "previous" time step to the // initial solution. - uPrev_ = uCur_; + solution_[/*historyIdx=*/1] = solution_[/*historyIdx=*/0]; } - void setHints(const Element &elem, - ElementVolumeVariables &prevVolVars, - ElementVolumeVariables &curVolVars) const + void setAllHints(ElementVariables &elemVars) const { - if (!enableHints_) + if (!enableHints_()) return; - int n = elem.template count<dim>(); - prevVolVars.resize(n); - curVolVars.resize(n); - for (int i = 0; i < n; ++i) { - int globalIdx = vertexMapper().map(elem, i, dim); - - if (!hintsUsable_[globalIdx]) { - curVolVars[i].setHint(NULL); - prevVolVars[i].setHint(NULL); - } - else { - curVolVars[i].setHint(&curHints_[globalIdx]); - prevVolVars[i].setHint(&prevHints_[globalIdx]); - } - } - }; + for (int historyIdx = 0; historyIdx < historySize; ++historyIdx) + setHints(elemVars, historyIdx); + } - void setHints(const Element &elem, - ElementVolumeVariables &curVolVars) const + void setHints(ElementVariables &elemVars, int historyIdx) const { - if (!enableHints_) + if (!enableHints_()) return; - int n = elem.template count<dim>(); - curVolVars.resize(n); - for (int i = 0; i < n; ++i) { - int globalIdx = vertexMapper().map(elem, i, dim); - - if (!hintsUsable_[globalIdx]) - curVolVars[i].setHint(NULL); - else - curVolVars[i].setHint(&curHints_[globalIdx]); + int numScv = elemVars.numScv(); + for (int scvIdx = 0; scvIdx < numScv; ++scvIdx) { + setHintsScv(elemVars, historyIdx, scvIdx); } + } + + void setHintsScv(ElementVariables &elemVars, int historyIdx, int scvIdx) const + { + int globalIdx = vertexMapper().map(elemVars.element(), scvIdx, dim); + + if (!hintsUsable_[globalIdx]) + elemVars.volVars(scvIdx, historyIdx).setHint(NULL); + else + elemVars.volVars(scvIdx, historyIdx) + .setHint(&hints_[historyIdx][globalIdx]); }; - void updatePrevHints() + void updateAllHints(const ElementVariables &elemVars) const { - if (!enableHints_) + if (!enableHints_()) return; - prevHints_ = curHints_; + for (int historyIdx = 0; historyIdx < historySize; ++historyIdx) { + updateHints(elemVars, historyIdx); + } }; - void updateCurHints(const Element &elem, - const ElementVolumeVariables &ev) const + void updateHints(const ElementVariables &elemVars, int historyIdx) const { - if (!enableHints_) + if (!enableHints_()) return; - - for (int i = 0; i < ev.size(); ++i) { - int globalIdx = vertexMapper().map(elem, i, dim); - curHints_[globalIdx] = ev[i]; - if (!hintsUsable_[globalIdx]) - prevHints_[globalIdx] = ev[i]; + + for (int scvIdx = 0; scvIdx < elemVars.numScv(); ++scvIdx) { + int globalIdx = vertexMapper().map(elemVars.element(), scvIdx, dim); + hints_[historyIdx][globalIdx] = elemVars.volVars(scvIdx, historyIdx); hintsUsable_[globalIdx] = true; } }; + void shiftHints() + { + for (int historyIdx = 0; historyIdx < historySize - 1; ++ historyIdx) + hints_[historyIdx + 1] = hints_[historyIdx]; + }; /*! * \brief Compute the global residual for an arbitrary solution @@ -226,10 +222,10 @@ public: Scalar globalResidual(SolutionVector &dest, const SolutionVector &u) { - SolutionVector tmp(curSol()); - curSol() = u; + SolutionVector tmp(solution(/*historyIdx=*/0)); + solution(/*historyIdx=*/0) = u; Scalar res = globalResidual(dest); - curSol() = tmp; + solution(/*historyIdx=*/0) = tmp; return res; } @@ -243,14 +239,16 @@ public: { dest = 0; + ElementVariables elemVars(this->problem_()); ElementIterator elemIt = gridView_().template begin<0>(); const ElementIterator elemEndIt = gridView_().template end<0>(); for (; elemIt != elemEndIt; ++elemIt) { - localResidual().eval(*elemIt); + elemVars.updateAll(*elemIt); + localResidual().eval(elemVars); - for (int i = 0; i < elemIt->template count<dim>(); ++i) { - int globalI = vertexMapper().map(*elemIt, i, dim); - dest[globalI] += localResidual().residual(i); + for (int scvIdx = 0; scvIdx < elemVars.numScv(); ++scvIdx) { + int globalI = vertexMapper().map(*elemIt, scvIdx, dim); + dest[globalI] += localResidual().residual(scvIdx); } }; @@ -279,11 +277,14 @@ public: void globalStorage(PrimaryVariables &dest) { dest = 0; - + + ElementVariables elemVars(this->problem_()); ElementIterator elemIt = gridView_().template begin<0>(); const ElementIterator elemEndIt = gridView_().template end<0>(); for (; elemIt != elemEndIt; ++elemIt) { - localResidual().evalStorage(*elemIt); + elemVars.updateFVElemGeom(*elemIt); + elemVars.updateScvVars(/*historyIdx=*/0); + localResidual().evalStorage(elemVars, /*historyIdx=*/0); for (int i = 0; i < elemIt->template count<dim>(); ++i) dest += localResidual().storageTerm()[i]; @@ -302,28 +303,16 @@ public: { return boxVolume_[globalIdx][0]; } /*! - * \brief Reference to the current solution as a block vector. - */ - const SolutionVector &curSol() const - { return uCur_; } - - /*! - * \brief Reference to the current solution as a block vector. - */ - SolutionVector &curSol() - { return uCur_; } - - /*! - * \brief Reference to the previous solution as a block vector. + * \brief Reference to the solution at a given history index as a block vector. */ - const SolutionVector &prevSol() const - { return uPrev_; } + const SolutionVector &solution(int historyIdx) const + { return solution_[historyIdx]; } /*! - * \brief Reference to the previous solution as a block vector. + * \brief Reference to the solution at a given history index as a block vector. */ - SolutionVector &prevSol() - { return uPrev_; } + SolutionVector &solution(int historyIdx) + { return solution_[historyIdx]; } /*! * \brief Returns the operator assembler for the global jacobian of @@ -374,7 +363,8 @@ public: */ Scalar primaryVarWeight(int vertIdx, int pvIdx) const { - return 1.0/std::max(std::abs(this->prevSol()[vertIdx][pvIdx]), 1.0); + Scalar absPv = std::abs(this->solution(/*historyIdx=*/1)[vertIdx][pvIdx]); + return 1.0/std::max(absPv, 1.0); } /*! @@ -419,8 +409,8 @@ public: NewtonController &controller) { #if HAVE_VALGRIND - for (size_t i = 0; i < curSol().size(); ++i) - Valgrind::CheckDefined(curSol()[i]); + for (size_t i = 0; i < solution(/*historyIdx=*/0).size(); ++i) + Valgrind::CheckDefined(solution(/*historyIdx=*/0)[i]); #endif // HAVE_VALGRIND asImp_().updateBegin(); @@ -433,8 +423,8 @@ public: asImp_().updateFailed(); #if HAVE_VALGRIND - for (size_t i = 0; i < curSol().size(); ++i) { - Valgrind::CheckDefined(curSol()[i]); + for (size_t i = 0; i < solution(/*historyIdx=*/0).size(); ++i) { + Valgrind::CheckDefined(solution(/*historyIdx=*/0)[i]); } #endif // HAVE_VALGRIND @@ -448,7 +438,9 @@ public: * which the actual model can overload. */ void updateBegin() - { } + { + updateBoundaryTypes_(); + } /*! @@ -469,8 +461,7 @@ public: // Reset the current solution to the one of the // previous time step so that we can start the next // update at a physically meaningful solution. - uCur_ = uPrev_; - curHints_ = prevHints_; + hints_[/*historyIdx=*/0] = hints_[/*historyIdx=*/1]; jacAsm_->reassembleAll(); }; @@ -485,10 +476,10 @@ public: void advanceTimeLevel() { // make the current solution the previous one. - uPrev_ = uCur_; - prevHints_ = curHints_; + solution_[/*historyIdx=*/1] = solution_[/*historyIdx=*/0]; - updatePrevHints(); + // shift the hints by one position in the history + shiftHints(); } /*! @@ -513,7 +504,7 @@ public: void deserialize(Restarter &res) { res.template deserializeEntities<dim>(asImp_(), this->gridView_()); - prevSol() = curSol(); + solution_[/*historyIdx=*/1] = solution_[/*historyIdx=*/0]; } /*! @@ -538,7 +529,7 @@ public: } for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) { - outstream << curSol()[vertIdx][eqIdx] << " "; + outstream << solution_[/*historyIdx=*/0][vertIdx][eqIdx] << " "; } }; @@ -560,7 +551,7 @@ public: DUNE_THROW(Dune::IOError, "Could not deserialize vertex " << vertIdx); - instream >> curSol()[vertIdx][eqIdx]; + instream >> solution_[/*historyIdx=*/0][vertIdx][eqIdx]; } }; @@ -602,6 +593,19 @@ public: jacAsm_->init(problem_()); } + /*! + * \brief Return a pointer to the BoundaryTypes for a given global + * vertex index or 0 if the vertex is not on the boundary. + */ + const BoundaryTypes *boundaryTypes(int globalIdx) const + { + static BoundaryTypes dummy; + int bvertIdx = boundaryVertexIndex_[globalIdx]; + if (bvertIdx < 0) + return &dummy; + return &boundaryTypes_[bvertIdx]; + } + /*! * \brief Update the weights of all primary variables within an * element given the complete set of volume variables @@ -609,8 +613,7 @@ public: * \param element The DUNE codim 0 entity * \param volVars All volume variables for the element */ - void updatePVWeights(const Element &element, - const ElementVolumeVariables &volVars) const + void updatePVWeights(const ElementVariables &elemVars) const { }; /*! @@ -641,10 +644,11 @@ public: ScalarField* def[numEq]; ScalarField* delta[numEq]; ScalarField* x[numEq]; - for (int i = 0; i < numEq; ++i) { - x[i] = writer.allocateManagedBuffer(numVertices); - delta[i] = writer.allocateManagedBuffer(numVertices); - def[i] = writer.allocateManagedBuffer(numVertices); + ScalarField* relError = writer.allocateManagedBuffer(numVertices); + for (int pvIdx = 0; pvIdx < numEq; ++pvIdx) { + x[pvIdx] = writer.allocateManagedBuffer(numVertices); + delta[pvIdx] = writer.allocateManagedBuffer(numVertices); + def[pvIdx] = writer.allocateManagedBuffer(numVertices); } VertexIterator vIt = this->gridView_().template begin<dim>(); @@ -652,17 +656,25 @@ public: for (; vIt != vEndIt; ++ vIt) { int globalIdx = vertexMapper().map(*vIt); - for (int i = 0; i < numEq; ++i) { - (*x[i])[globalIdx] = u[globalIdx][i]; - (*delta[i])[globalIdx] = - deltaU[globalIdx][i]; - (*def[i])[globalIdx] = globalResid[globalIdx][i]; + for (int pvIdx = 0; pvIdx < numEq; ++pvIdx) { + (*x[pvIdx])[globalIdx] = u[globalIdx][pvIdx]; + (*delta[pvIdx])[globalIdx] = + - deltaU[globalIdx][pvIdx]; + (*def[pvIdx])[globalIdx] = globalResid[globalIdx][pvIdx]; } + + PrimaryVariables uOld(u[globalIdx]); + PrimaryVariables uNew(uOld - deltaU[globalIdx]); + (*relError)[globalIdx] = asImp_().relativeErrorVertex(globalIdx, + uOld, + uNew); } - for (int i = 0; i < numEq; ++i) { - writer.attachVertexData(*x[i], (boost::format("x_%i")%i).str().c_str()); - writer.attachVertexData(*delta[i], (boost::format("delta_%i")%i).str().c_str()); - writer.attachVertexData(*def[i], (boost::format("defect_%i")%i).str().c_str()); + writer.attachVertexData(*relError, "relative Error"); + for (int pvIdx = 0; pvIdx < numEq; ++pvIdx) { + writer.attachVertexData(*x[pvIdx], (boost::format("x_%i")%pvIdx).str().c_str()); + writer.attachVertexData(*delta[pvIdx], (boost::format("delta_%i")%pvIdx).str().c_str()); + writer.attachVertexData(*def[pvIdx], (boost::format("defect_%i")%pvIdx).str().c_str()); } asImp_().addOutputVtkFields(u, writer); @@ -684,7 +696,7 @@ public: void addOutputVtkFields(const SolutionVector &sol, MultiWriter &writer) { - typedef Dune::BlockVector<Dune::FieldVector<Scalar, 1> > ScalarField; + typedef Dune::BlockVector<Dune::FieldVector<double, 1> > ScalarField; // create the required scalar fields unsigned numVertices = this->gridView_().size(dim); @@ -716,6 +728,9 @@ public: { return problem_().gridView(); } protected: + static bool enableHints_() + { return GET_PARAM(TypeTag, bool, EnableHints); } + /*! * \brief A reference to the problem on which the model is applied. */ @@ -739,13 +754,83 @@ protected: LocalResidual &localResidual_() { return localJacobian_.localResidual(); } + /*! + * \brief Updates the stuff which determines a vertex' or + * element's boundary type + */ + void updateBoundaryTypes_() + { + // resize the vectors + boundaryVertexIndex_.resize(numDofs()); + std::fill(boundaryVertexIndex_.begin(), + boundaryVertexIndex_.end(), + -1); + + int numBoundaryVertices = 0; + ElementVariables elemVars(problem_()); + + // loop over all elements of the grid + ElementIterator elemIt = gridView_().template begin<0>(); + const ElementIterator elemEndIt = gridView_().template end<0>(); + for (; elemIt != elemEndIt; ++elemIt) { + // do nothing if the element does not have boundary intersections + if (!elemIt->hasBoundaryIntersections()) + continue; + + // retrieve the reference element for the current element + const Element &elem = *elemIt; + Dune::GeometryType geoType = elem.geometry().type(); + const ReferenceElement &refElem = ReferenceElements::general(geoType); + + elemVars.updateFVElemGeom(*elemIt); + + // loop over all intersections of the element + IntersectionIterator isIt = gridView_().ibegin(elem); + const IntersectionIterator &endIt = gridView_().iend(elem); + for (; isIt != endIt; ++isIt) + { + // do nothing if the face is _not_ on the boundary + if (!isIt->boundary()) + continue; + + // loop over all vertices of the intersection + int faceIdx = isIt->indexInInside(); + int numFaceVerts = refElem.size(faceIdx, 1, dim); + for (int faceVertIdx = 0; + faceVertIdx < numFaceVerts; + ++faceVertIdx) + { + // find the local element index of the face's + // vertex + int scvIdx = refElem.subEntity(/*entityIdx=*/faceIdx, + /*entityCodim=*/1, + /*subEntityIdx=*/faceVertIdx, + /*subEntityCodim=*/dim); + int globalIdx = vertexMapper().map(*elemIt, scvIdx, /*codim=*/dim); + if (boundaryVertexIndex_[globalIdx] >= 0) + continue; // vertex has already been visited + + // add a BoundaryTypes object + if (boundaryTypes_.size() <= numBoundaryVertices) + boundaryTypes_.resize(numBoundaryVertices + 1); + BoundaryTypes &bTypes = boundaryTypes_[numBoundaryVertices]; + boundaryVertexIndex_[globalIdx] = numBoundaryVertices; + ++numBoundaryVertices; + + problem_().boundaryTypes(bTypes, elemVars, scvIdx); + } // loop over intersection's vertices + } // loop over intersections + } // loop over elements + }; + /*! * \brief Applies the initial solution for all vertices of the grid. */ void applyInitialSolution_() { // first set the whole domain to zero - uCur_ = Scalar(0.0); + SolutionVector &uCur = solution(/*historyIdx=*/0); + uCur = Scalar(0.0); boxVolume_ = Scalar(0.0); FVElementGeometry fvElemGeom; @@ -785,8 +870,8 @@ protected: // will be the arithmetic mean. initVal *= fvElemGeom.subContVol[scvIdx].volume; boxVolume_[globalIdx] += fvElemGeom.subContVol[scvIdx].volume; - uCur_[globalIdx] += initVal; - Valgrind::CheckDefined(uCur_[globalIdx]); + uCur[globalIdx] += initVal; + Valgrind::CheckDefined(uCur[globalIdx]); } } @@ -801,7 +886,7 @@ protected: Dune::ForwardCommunication); VertexHandleSum<PrimaryVariables, SolutionVector, VertexMapper> - sumPVHandle(uCur_, vertexMapper()); + sumPVHandle(uCur, vertexMapper()); gridView().communicate(sumPVHandle, Dune::InteriorBorder_InteriorBorder_Interface, Dune::ForwardCommunication); @@ -810,15 +895,14 @@ protected: // divide all primary variables by the volume of their boxes int n = gridView_().size(dim); for (int i = 0; i < n; ++i) { - uCur_[i] /= boxVolume(i); + uCur[i] /= boxVolume(i); } } // the hint cache for the previous and the current volume // variables mutable std::vector<bool> hintsUsable_; - mutable std::vector<VolumeVariables> curHints_; - mutable std::vector<VolumeVariables> prevHints_; + mutable std::vector<VolumeVariables> hints_[historySize]; /*! * \brief Returns whether messages should be printed @@ -843,13 +927,13 @@ protected: // cur is the current iterative solution, prev the converged // solution of the previous time step - SolutionVector uCur_; - SolutionVector uPrev_; + SolutionVector solution_[historySize]; - Dune::BlockVector<Dune::FieldVector<Scalar, 1> > boxVolume_; + // all the index of the BoundaryTypes object for a vertex + std::vector<int> boundaryVertexIndex_; + std::vector<BoundaryTypes> boundaryTypes_; -private: - bool enableHints_; + Dune::BlockVector<Dune::FieldVector<Scalar, 1> > boxVolume_; }; } diff --git a/dumux/boxmodels/common/boxproblem.hh b/dumux/boxmodels/common/boxproblem.hh index b8284c38f341b1f8a8fc5d49a4c94ea855524ceb..9a5fbaab9b1e5e503fcb0e0236ffcad75652af4c 100644 --- a/dumux/boxmodels/common/boxproblem.hh +++ b/dumux/boxmodels/common/boxproblem.hh @@ -60,7 +60,7 @@ private: typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementMapper)) ElementMapper; typedef typename GET_PROP_TYPE(TypeTag, PTAG(PrimaryVariables)) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVolumeVariables)) ElementVolumeVariables; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVariables)) ElementVariables; typedef typename GET_PROP_TYPE(TypeTag, PTAG(FVElementGeometry)) FVElementGeometry; typedef typename GET_PROP_TYPE(TypeTag, PTAG(BoundaryTypes)) BoundaryTypes; @@ -139,6 +139,28 @@ public: model().init(asImp_()); } + /*! + * \brief Evaluate the boundary conditions for a dirichlet + * control volume. + * + * \param values The dirichlet values for the primary variables + * \param context The local context. Only the element() and the fvElemGeom() methods are valid at this point + * \param localIdx The local index of the entity neighboring the Dirichlet boundary. + * + * For this method, the \a values parameter stores primary variables. + */ + template <class Context> + DUNE_DEPRECATED + void boundaryTypes(BoundaryTypes &values, + const Context &context, + int localIdx) const + { + const auto vPtr = context.element().template subEntity<dim>(localIdx); + + // forward it to the method which only takes the global coordinate + asImp_().boundaryTypes(values, *vPtr); + } + /*! * \brief Specifies which kind of boundary condition should be * used for which equation on a given boundary segment. @@ -170,6 +192,27 @@ public: "a boundaryTypes() method."); } + /*! + * \brief Evaluate the boundary conditions for a dirichlet + * control volume. + * + * \param values The dirichlet values for the primary variables + * \param context The local context. Only the element() and the fvElemGeom() methods are valid at this point + * \param localIdx The local index of the entity neighboring the Dirichlet boundary. + * + * For this method, the \a values parameter stores primary variables. + */ + template <class Context> + DUNE_DEPRECATED + void dirichlet(PrimaryVariables &values, + const Context &context, + int localIdx) const + { + const auto vPtr = context.element().template subEntity<dim>(localIdx); + + // forward it to the method which only takes the global coordinate + asImp_().dirichlet(values, *vPtr); + } /*! * \brief Evaluate the boundary conditions for a dirichlet @@ -180,6 +223,7 @@ public: * * For this method, the \a values parameter stores primary variables. */ + DUNE_DEPRECATED void dirichlet(PrimaryVariables &values, const Vertex &vertex) const { @@ -198,6 +242,7 @@ public: * * For this method, the \a values parameter stores primary variables. */ + DUNE_DEPRECATED void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &pos) const { @@ -209,6 +254,25 @@ public: "a dirichlet() method."); } + template <class Context> + DUNE_DEPRECATED + // if you get an deprecated warning here, please use context + // objects to specify your problem! + void neumann(PrimaryVariables &priVars, + const Context &context, + const Intersection &is, + int localIdx, + int boundaryIndex) const + { + return asImp_().boxSDNeumann(priVars, + context.element(), + context.fvElemGeom(), + is, + localIdx, + boundaryIndex, + context); + }; + /*! * \brief Evaluate the boundary conditions for a neumann * boundary segment. @@ -234,7 +298,8 @@ public: const Intersection &is, int scvIdx, int boundaryFaceIdx, - const ElementVolumeVariables &elemVolVars) const + const ElementVariables &elemVars) const + DUNE_DEPRECATED { // forward it to the interface without the volume variables asImp_().neumann(values, @@ -265,6 +330,7 @@ public: const Intersection &is, int scvIdx, int boundaryFaceIdx) const + DUNE_DEPRECATED { // forward it to the interface with only the global position asImp_().neumannAtPos(values, fvElemGeom.boundaryFace[boundaryFaceIdx].ipGlobal); @@ -282,6 +348,7 @@ public: */ void neumannAtPos(PrimaryVariables &values, const GlobalPosition &pos) const + DUNE_DEPRECATED { // Throw an exception (there is no reasonable default value // for Neumann conditions) @@ -291,6 +358,21 @@ public: "a neumannAtPos() method."); } + template <class Context> + // if you get an deprecated warning here, please use context + // objects to specify your problem! + DUNE_DEPRECATED + void source(PrimaryVariables &priVars, + const Context &context, + int localIdx) const + { + return asImp_().boxSDSource(priVars, + context.element(), + context.fvElemGeom(), + localIdx, + context); + }; + /*! * \brief Evaluate the source term for all phases within a given * sub-control-volume. @@ -313,10 +395,11 @@ public: const Element &element, const FVElementGeometry &fvElemGeom, int scvIdx, - const ElementVolumeVariables &elemVolVars) const + const ElementVariables &elemVars) const + DUNE_DEPRECATED { // forward to solution independent, box specific interface - asImp_().source(values, element, fvElemGeom, scvIdx); + asImp_().source(values, elemVars, scvIdx); } /*! @@ -336,6 +419,7 @@ public: const Element &element, const FVElementGeometry &fvElemGeom, int scvIdx) const + DUNE_DEPRECATED { // forward to generic interface asImp_().sourceAtPos(values, fvElemGeom.subContVol[scvIdx].global); @@ -356,6 +440,7 @@ public: */ void sourceAtPos(PrimaryVariables &values, const GlobalPosition &pos) const + DUNE_DEPRECATED { DUNE_THROW(Dune::InvalidStateException, "The problem does not provide " @@ -411,6 +496,28 @@ public: * thought as pipes with a cross section of 1 m^2 and 2D problems * are assumed to extend 1 m to the back. */ + template <class Context> + // if you get an deprecated warning here, please use context + // objects to specify your problem! + DUNE_DEPRECATED + Scalar extrusionFactor(const Context &context, + int localIdx) const + { + return asImp_().boxExtrusionFactor(context.element(), + context.fvElemGeom(), + localIdx); + }; + + /*! + * \brief Return how much the domain is extruded at a given sub-control volume. + * + * This means the factor by which a lower-dimensional (1D or 2D) + * entity needs to be expanded to get a full dimensional cell. The + * default is 1.0 which means that 1D problems are actually + * thought as pipes with a cross section of 1 m^2 and 2D problems + * are assumed to extend 1 m to the back. + */ + DUNE_DEPRECATED Scalar boxExtrusionFactor(const Element &element, const FVElementGeometry &fvElemGeom, int scvIdx) const @@ -768,7 +875,7 @@ public: Scalar t = timeManager().time() + timeManager().timeStepSize(); createResultWriter_(); resultWriter_->beginWrite(t); - model().addOutputVtkFields(model().curSol(), *resultWriter_); + model().addOutputVtkFields(model().solution(/*historyIdx=*/0), *resultWriter_); asImp_().addOutputVtkFields(); resultWriter_->endWrite(); } diff --git a/dumux/boxmodels/common/boxproperties.hh b/dumux/boxmodels/common/boxproperties.hh index 466a281393a39b24f57f3278fa3ab2e2a0da051d..ae75bb159e69f9254a2047f5e42be85f6d10ea81 100644 --- a/dumux/boxmodels/common/boxproperties.hh +++ b/dumux/boxmodels/common/boxproperties.hh @@ -74,7 +74,7 @@ NEW_PROP_TAG(SolutionVector); //!< Vector containing all primary variable vector NEW_PROP_TAG(ElementSolutionVector); //!< A vector of primary variables within a sub-control volume NEW_PROP_TAG(VolumeVariables); //!< The secondary variables within a sub-control volume -NEW_PROP_TAG(ElementVolumeVariables); //!< The secondary variables of all sub-control volumes in an element +NEW_PROP_TAG(ElementVariables); //!< The secondary variables of all sub-control volumes in an element NEW_PROP_TAG(FluxVariables); //!< Data required to calculate a flux over a face NEW_PROP_TAG(BoundaryVariables); //!< Data required to calculate fluxes over boundary faces (outflow) @@ -121,12 +121,15 @@ NEW_PROP_TAG(EnableHints); // mappers from local to global indices -//! maper for vertices +//! mapper for vertices NEW_PROP_TAG(VertexMapper); -//! maper for elements +//! mapper for elements NEW_PROP_TAG(ElementMapper); -//! maper for degrees of freedom +//! mapper for degrees of freedom NEW_PROP_TAG(DofMapper); + +//! The history size required by the time discretization +NEW_PROP_TAG(TimeDiscHistorySize); } } diff --git a/dumux/boxmodels/common/boxpropertydefaults.hh b/dumux/boxmodels/common/boxpropertydefaults.hh index f1517d599b050e9aa01eb02daa6e6af3fc25fcbd..c5253660718029c693d3857d5357434224733098 100644 --- a/dumux/boxmodels/common/boxpropertydefaults.hh +++ b/dumux/boxmodels/common/boxpropertydefaults.hh @@ -124,7 +124,7 @@ SET_TYPE_PROP(BoxModel, VolumeVariables, Dumux::BoxVolumeVariables<TypeTag>); /*! * \brief An array of secondary variable containers. */ -SET_TYPE_PROP(BoxModel, ElementVolumeVariables, Dumux::BoxElementVolumeVariables<TypeTag>); +SET_TYPE_PROP(BoxModel, ElementVariables, Dumux::BoxElementVariables<TypeTag>); /*! * \brief Boundary types at a single degree of freedom. @@ -185,6 +185,8 @@ SET_INT_PROP(BoxModel, LinearSolverMaxIterations, 250); //! set number of equations of the mathematical model as default SET_INT_PROP(BoxModel, LinearSolverBlockSize, GET_PROP_VALUE(TypeTag, PTAG(NumEq))); +//! Set the history size of the time discretiuation to 2 (for implicit euler) +SET_INT_PROP(BoxModel, TimeDiscHistorySize, 2); } // namespace Properties } // namespace Dumux diff --git a/dumux/boxmodels/common/boxvolumevariables.hh b/dumux/boxmodels/common/boxvolumevariables.hh index 626d7a9801129d1d7e1481966f329650742b52fe..cf85043fbc42f154f0837b096f54545d837b37b4 100644 --- a/dumux/boxmodels/common/boxvolumevariables.hh +++ b/dumux/boxmodels/common/boxvolumevariables.hh @@ -49,6 +49,7 @@ class BoxVolumeVariables typedef typename GET_PROP_TYPE(TypeTag, PTAG(FVElementGeometry)) FVElementGeometry; typedef typename GET_PROP_TYPE(TypeTag, PTAG(PrimaryVariables)) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, PTAG(ElementVariables)) ElementVariables; public: // default constructor @@ -118,15 +119,13 @@ public: * phase state in the 2p2c model) */ void update(const PrimaryVariables &priVars, - const Problem &problem, - const Element &element, - const FVElementGeometry &elemGeom, + const ElementVariables &elemVars, int scvIdx, - bool isOldSol) + int historyIdx) { Valgrind::CheckDefined(priVars); primaryVars_ = priVars; - extrusionFactor_ = problem.boxExtrusionFactor(element, elemGeom, scvIdx); + extrusionFactor_ = elemVars.problem().extrusionFactor(elemVars, scvIdx); } /*! diff --git a/dumux/common/timemanager.hh b/dumux/common/timemanager.hh index 1bbf74c58004eb4382ac52ccd333ae44eac5bb05..a7d244a324b8585a0f3e273165420724cd8fec35 100644 --- a/dumux/common/timemanager.hh +++ b/dumux/common/timemanager.hh @@ -379,7 +379,7 @@ public: if (verbose_) { std::cout << boost::format("Time step %d done. Wall time:%.4g, time:%.4g, time step size:%.4g\n") - %timeStepIndex()%timer.elapsed()%time()%dt; + %timeStepIndex()%double(timer.elapsed())%double(time())%double(dt); } // write restart file if mandated by the problem diff --git a/dumux/linear/overlappingscalarproduct.hh b/dumux/linear/overlappingscalarproduct.hh index 2f0360e938678d9022f6acc49d9333b37c7880fc..71bfaff5048ce2fb088c2219016e48d5802190fc 100644 --- a/dumux/linear/overlappingscalarproduct.hh +++ b/dumux/linear/overlappingscalarproduct.hh @@ -67,8 +67,8 @@ public: double norm(const OverlappingBlockVector &x) { - double tmp = dot(x, x); - return std::sqrt(tmp); + field_type tmp = std::sqrt(dot(x, x)); + return tmp; }; private: diff --git a/dumux/material/spatialparameters/boxspatialparameters.hh b/dumux/material/spatialparameters/boxspatialparameters.hh index 28cf38036859772409466dfb3bda6bdfefc5868b..79e4cd8caf27a84114a62bbd492595c6e5969bd1 100644 --- a/dumux/material/spatialparameters/boxspatialparameters.hh +++ b/dumux/material/spatialparameters/boxspatialparameters.hh @@ -72,20 +72,30 @@ public: * \brief Function for defining the parameters needed by constitutive relationships (kr-Sw, pc-Sw, etc.). * * \return the material parameters object - * \param element The element */ + template <class Context> + DUNE_DEPRECATED + const MaterialLawParams& materialLawParams(const Context &context, int localIdx) const + { + return asImp_().materialLawParams(context.element(), + context.fvElemGeom(), + localIdx); + } + + DUNE_DEPRECATED const MaterialLawParams& materialLawParams(const Element &element, - const FVElementGeometry &fvElemGeom, - int scvIdx) const + const FVElementGeometry &fvElemGeom, + int localIdx) const { - return asImp_().materialLawParamsAtPos(element.geometry().center()); + return asImp_().materialLawParams(fvElemGeom.subContVol[localIdx].global); } + /*! * \brief Function for defining the parameters needed by constitutive relationships (kr-Sw, pc-Sw, etc.). * - * \return the material parameters object * \param globalPos The position of the center of the element + * \return the material parameters object */ const MaterialLawParams& materialLawParamsAtPos(const GlobalPosition& globalPos) const { diff --git a/dumux/material/spatialparameters/boxspatialparameters1p.hh b/dumux/material/spatialparameters/boxspatialparameters1p.hh index a70a3a4ae56406a2fc0d5b1e0e99019af536efb1..fe7232fc781a5b104778f6707727c3c33ff0f45f 100644 --- a/dumux/material/spatialparameters/boxspatialparameters1p.hh +++ b/dumux/material/spatialparameters/boxspatialparameters1p.hh @@ -66,6 +66,7 @@ class BoxSpatialParametersOneP typedef typename GridView::ctype CoordScalar; typedef Dune::FieldMatrix<Scalar, dimWorld, dimWorld> Tensor; typedef Dune::FieldVector<CoordScalar,dimWorld> GlobalPosition; + typedef Dune::FieldVector<Scalar,dimWorld> Vector; public: BoxSpatialParametersOneP(const GridView &gv) @@ -74,53 +75,6 @@ public: ~BoxSpatialParametersOneP() {} - /*! - * \brief Returns the factor by which the volume of a sub control - * volume needs to be multiplied in order to get cubic - * meters. - * - * \param element The current finite element - * \param fvElemGeom The current finite volume geometry of the element - * \param scvIdx The index sub-control volume face where the - * factor ought to be calculated. - * - * By default that's just 1.0 - */ - Scalar extrusionFactorScv(const Element &element, - const FVElementGeometry &fvElemGeom, - int scvIdx) const - DUNE_DEPRECATED // use the extrusion factor of the volume variables - { return 1.0; } - - /*! - * \brief Returns the factor by which the area of a sub control - * volume face needs to be multiplied in order to get - * square meters. - * - * \param element The current finite element - * \param fvElemGeom The current finite volume geometry of the element - * \param scvfIdx The index sub-control volume face where the - * factor ought to be calculated. - * - * By default it is the arithmetic mean of the extrusion factor of - * the face's two sub-control volumes. - */ - Scalar extrusionFactorScvf(const Element &element, - const FVElementGeometry &fvElemGeom, - int scvfIdx) const - DUNE_DEPRECATED // use the extrusion factor of the volume variables - { - return - 0.5 * - (asImp_().extrusionFactorScv(element, - fvElemGeom, - fvElemGeom.subContVolFace[scvfIdx].i) - + - asImp_().extrusionFactorScv(element, - fvElemGeom, - fvElemGeom.subContVolFace[scvfIdx].j)); - } - /*! * \brief Averages the intrinsic permeability (Scalar). * \param result averaged intrinsic permeability @@ -156,15 +110,26 @@ public: result[i][j] = harmonicMean(K1[i][j], K2[i][j]); } + template <class Context> + const Tensor &intrinsicPermeability(const Context &context, + int localIdx) const + { + return intrinsicPermeability(context.element(), + context.fvElemGeom(), + localIdx); + + } + /*! * \brief Function for defining the intrinsic (absolute) permeability. * * \return intrinsic (absolute) permeability * \param element The element */ - const Tensor& intrinsicPermeability (const Element &element, - const FVElementGeometry &fvElemGeom, - int scvIdx) const + DUNE_DEPRECATED + const Tensor &intrinsicPermeability(const Element &element, + const FVElementGeometry &fvElemGeom, + int scvIdx) const { return asImp_().intrinsicPermeabilityAtPos(element.geometry().center()); } @@ -175,6 +140,7 @@ public: * \return intrinsic (absolute) permeability * \param globalPos The position of the center of the element */ + DUNE_DEPRECATED const Tensor& intrinsicPermeabilityAtPos (const GlobalPosition& globalPos) const { DUNE_THROW(Dune::InvalidStateException, @@ -182,15 +148,26 @@ public: "a intrinsicPermeabilityAtPos() method."); } + template <class Context> + Scalar porosity(const Context &context, + int localIdx) const + { + return porosity(context.element(), + context.fvElemGeom(), + localIdx); + + } + /*! * \brief Function for defining the porosity. * * \return porosity * \param element The element */ + DUNE_DEPRECATED Scalar porosity(const Element &element, - const FVElementGeometry &fvElemGeom, - int scvIdx) const + const FVElementGeometry &fvElemGeom, + int scvIdx) const { return asImp_().porosityAtPos(element.geometry().center()); } @@ -201,6 +178,7 @@ public: * \return porosity * \param globalPos The position of the center of the element */ + DUNE_DEPRECATED Scalar porosityAtPos(const GlobalPosition& globalPos) const { DUNE_THROW(Dune::InvalidStateException, diff --git a/dumux/nonlinear/newtonmethod.hh b/dumux/nonlinear/newtonmethod.hh index a083ef605c76f3e23f4067e2378b859b1380a60d..2165c39f8b8f10ad9032585101681148b13e230e 100644 --- a/dumux/nonlinear/newtonmethod.hh +++ b/dumux/nonlinear/newtonmethod.hh @@ -116,7 +116,7 @@ public: protected: bool execute_(NewtonController &ctl) { - SolutionVector &uCurrentIter = model().curSol(); + SolutionVector &uCurrentIter = model().solution(/*historyIdx=*/0); SolutionVector uLastIter(uCurrentIter); SolutionVector deltaU(uCurrentIter); diff --git a/test/boxmodels/2p/lensproblem.hh b/test/boxmodels/2p/lensproblem.hh index dab4dc78d7b4ae513a3526ccbcceb3453ff43b77..d8bc6f25412d514a453bb6b655d306444fda66ec 100644 --- a/test/boxmodels/2p/lensproblem.hh +++ b/test/boxmodels/2p/lensproblem.hh @@ -25,10 +25,11 @@ * \brief Soil contamination problem where DNAPL infiltrates a fully * water saturated medium. */ - #ifndef DUMUX_LENSPROBLEM_HH #define DUMUX_LENSPROBLEM_HH +//#include <dumux/common/quad.hh> + #if HAVE_UG #include <dune/grid/uggrid.hh> #endif @@ -57,6 +58,8 @@ namespace Properties { NEW_TYPE_TAG(LensProblem, INHERITS_FROM(BoxTwoP, LensSpatialParameters)); +//SET_TYPE_PROP(LensProblem, Scalar, quad); + // Set the grid type #if 0// HAVE_UG SET_TYPE_PROP(LensProblem, Grid, Dune::UGGrid<2>); @@ -243,6 +246,7 @@ public: * * This problem assumes a uniform temperature of 10 degrees Celsius. */ + using ParentType::temperature; Scalar temperature() const { return temperature_; }; diff --git a/test/boxmodels/2p/lensspatialparameters.hh b/test/boxmodels/2p/lensspatialparameters.hh index d0a34f0f153adba60b1a2aa9e2c56d045399e6de..ad82f044eac3d4e8c74eb3815bcbba5b81b07787 100644 --- a/test/boxmodels/2p/lensspatialparameters.hh +++ b/test/boxmodels/2p/lensspatialparameters.hh @@ -135,27 +135,24 @@ public: * \param scvIdx The index sub-control volume face where the * intrinsic velocity ought to be calculated. */ - Scalar intrinsicPermeability(const Element &element, - const FVElementGeometry &fvElemGeom, - int scvIdx) const + template <class Context> + Scalar intrinsicPermeability(const Context &context, int localIdx) const { - const GlobalPosition &globalPos = fvElemGeom.subContVol[scvIdx].global; + const GlobalPosition &globalPos = context.pos(localIdx); if (isInLens_(globalPos)) return lensK_; return outerK_; } - Scalar porosity(const Element &element, - const FVElementGeometry &fvElemGeom, - int scvIdx) const + template <class Context> + Scalar porosity(const Context &context, int localIdx) const { return 0.4; } // return the parameter object for the Brooks-Corey material law which depends on the position - const MaterialLawParams& materialLawParams(const Element &element, - const FVElementGeometry &fvElemGeom, - int scvIdx) const + template <class Context> + const MaterialLawParams& materialLawParams(const Context &context, int localIdx) const { - const GlobalPosition &globalPos = fvElemGeom.subContVol[scvIdx].global; + const GlobalPosition &globalPos = context.pos(localIdx); if (isInLens_(globalPos)) return lensMaterialParams_;