LCOV - code coverage report
Current view: top level - /builds/ug4-project/ugcore/ug4-new/plugins/ConvectionDiffusion/fv1 - convection_diffusion_fv1.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 499 0
Test Date: 2026-11-07 06:16:00 Functions: 0.0 % 1005 0

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 2010-2015:  G-CSC, Goethe University Frankfurt
       3              :  * Author: Andreas Vogel
       4              :  * 
       5              :  * This file is part of UG4.
       6              :  * 
       7              :  * UG4 is free software: you can redistribute it and/or modify it under the
       8              :  * terms of the GNU Lesser General Public License version 3 (as published by the
       9              :  * Free Software Foundation) with the following additional attribution
      10              :  * requirements (according to LGPL/GPL v3 §7):
      11              :  * 
      12              :  * (1) The following notice must be displayed in the Appropriate Legal Notices
      13              :  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
      14              :  * 
      15              :  * (2) The following notice must be displayed at a prominent place in the
      16              :  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
      17              :  * 
      18              :  * (3) The following bibliography is recommended for citation and must be
      19              :  * preserved in all covered files:
      20              :  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
      21              :  *   parallel geometric multigrid solver on hierarchically distributed grids.
      22              :  *   Computing and visualization in science 16, 4 (2013), 151-164"
      23              :  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
      24              :  *   flexible software system for simulating pde based models on high performance
      25              :  *   computers. Computing and visualization in science 16, 4 (2013), 165-179"
      26              :  * 
      27              :  * This program is distributed in the hope that it will be useful,
      28              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      29              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      30              :  * GNU Lesser General Public License for more details.
      31              :  */
      32              : 
      33              : #include "convection_diffusion_fv1.h"
      34              : 
      35              : #include "lib_disc/spatial_disc/disc_util/geom_provider.h"
      36              : #include "lib_disc/spatial_disc/disc_util/fv1_geom.h"
      37              : #include "lib_disc/spatial_disc/disc_util/hfv1_geom.h"
      38              : #include "lib_disc/spatial_disc/disc_util/conv_shape.h"
      39              : 
      40              : namespace ug{
      41              : namespace ConvectionDiffusionPlugin{
      42              : 
      43              : DebugID DID_CONV_DIFF_FV1("CONV_DIFF_FV1");
      44              : 
      45              : ////////////////////////////////////////////////////////////////////////////////
      46              : //      general
      47              : ////////////////////////////////////////////////////////////////////////////////
      48              : 
      49              : template<typename TDomain>
      50            0 : ConvectionDiffusionFV1<TDomain>::
      51              : ConvectionDiffusionFV1(const char* functions, const char* subsets)
      52              :  : ConvectionDiffusionBase<TDomain>(functions,subsets),
      53            0 :    m_spConvShape(new ConvectionShapesNoUpwind<dim>),
      54            0 :    m_bNonRegularGrid(false), m_bCondensedFV(false)
      55              : {
      56              :         register_all_funcs(m_bNonRegularGrid);
      57            0 : }
      58              : 
      59              : template<typename TDomain>
      60            0 : void ConvectionDiffusionFV1<TDomain>::
      61              : prepare_setting(const std::vector<LFEID>& vLfeID, bool bNonRegularGrid)
      62              : {
      63              : //      check number
      64            0 :         if(vLfeID.size() != 1)
      65            0 :                 UG_THROW("ConvectionDiffusion: Wrong number of functions given. "
      66              :                                 "Need exactly "<<1);
      67              : 
      68            0 :         if(vLfeID[0].order() != 1 || vLfeID[0].type() != LFEID::LAGRANGE)
      69            0 :                 UG_THROW("ConvectionDiffusion FV Scheme only implemented for 1st order.");
      70              : 
      71              : //      remember
      72            0 :         m_bNonRegularGrid = bNonRegularGrid;
      73              : 
      74              : //      update assemble functions
      75              :         register_all_funcs(m_bNonRegularGrid);
      76            0 : }
      77              : 
      78              : template<typename TDomain>
      79            0 : bool ConvectionDiffusionFV1<TDomain>::
      80              : use_hanging() const
      81              : {
      82            0 :         return true;
      83              : }
      84              : 
      85              : ////////////////////////////////////////////////////////////////////////////////
      86              : // Assembling functions
      87              : ////////////////////////////////////////////////////////////////////////////////
      88              : 
      89              : template<typename TDomain>
      90            0 : void ConvectionDiffusionFV1<TDomain>::
      91              : prep_assemble_loop()
      92              : {
      93            0 :         if (m_sss_mngr.valid ())
      94              :         //      reset the markers of the point sources and sinks (as there are no marks for the lines)
      95              :                 m_sss_mngr->init_all_point_sss ();
      96            0 : }
      97              : 
      98              : template<typename TDomain>
      99              : template<typename TElem, typename TFVGeom>
     100            0 : void ConvectionDiffusionFV1<TDomain>::
     101              : prep_elem_loop(const ReferenceObjectID roid, const int si)
     102              : {
     103              : 
     104              : //      check, that upwind has been set
     105              : //TODO: It is really used only if we have the convection
     106            0 :         if(m_spConvShape.invalid())
     107            0 :                 UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:"
     108              :                                                 " Upwind has not been set.");
     109              : 
     110              : //      set local positions
     111              :         if(!TFVGeom::usesHangingNodes)
     112              :         {
     113              :                 static const int refDim = TElem::dim;
     114            0 :                 TFVGeom& geo = GeomProvider<TFVGeom>::get();
     115              :                 const MathVector<refDim>* vSCVFip = geo.scvf_local_ips();
     116              :                 const size_t numSCVFip = geo.num_scvf_ips();
     117              :                 const MathVector<refDim>* vSCVip = geo.scv_local_ips();
     118              :                 const size_t numSCVip = geo.num_scv_ips();
     119            0 :                 m_imDiffusion.template          set_local_ips<refDim>(vSCVFip,numSCVFip, false);
     120            0 :                 m_imVelocity.template           set_local_ips<refDim>(vSCVFip,numSCVFip, false);
     121            0 :                 m_imFlux.template                       set_local_ips<refDim>(vSCVFip,numSCVFip, false);
     122            0 :                 m_imSource.template             set_local_ips<refDim>(vSCVip,numSCVip, false);
     123            0 :                 m_imVectorSource.template       set_local_ips<refDim>(vSCVFip,numSCVFip, false);
     124            0 :                 m_imReactionRate.template       set_local_ips<refDim>(vSCVip,numSCVip, false);
     125            0 :                 m_imReaction.template           set_local_ips<refDim>(vSCVip,numSCVip, false);
     126            0 :                 m_imReactionRateExpl.template set_local_ips<refDim>(vSCVip,numSCVip, false);
     127            0 :                 m_imReactionExpl.template       set_local_ips<refDim>(vSCVip,numSCVip, false);
     128            0 :                 m_imSourceExpl.template         set_local_ips<refDim>(vSCVip,numSCVip, false);
     129            0 :                 m_imMassScale.template          set_local_ips<refDim>(vSCVip,numSCVip, false);
     130            0 :                 m_imMass.template                       set_local_ips<refDim>(vSCVip,numSCVip, false);
     131              : 
     132              :                 //      init upwind for element type
     133            0 :                 if(!m_spConvShape->template set_geometry_type<TFVGeom>(geo))
     134            0 :                         UG_THROW("ConvectionDiffusionFV1::prep_elem_loop:"
     135              :                                                 " Cannot init upwind for element type.");
     136              :         }
     137            0 : }
     138              : 
     139              : template<typename TDomain>
     140              : template<typename TElem, typename TFVGeom>
     141            0 : void ConvectionDiffusionFV1<TDomain>::
     142              : fsh_elem_loop()
     143            0 : {}
     144              : 
     145              : template<typename TDomain>
     146              : template<typename TElem, typename TFVGeom>
     147            0 : void ConvectionDiffusionFV1<TDomain>::
     148              : prep_elem(const LocalVector& u, GridObject* elem, const ReferenceObjectID roid, const MathVector<dim> vCornerCoords[])
     149              : {
     150              : //      Update Geometry for this element
     151            0 :         static TFVGeom& geo = GeomProvider<TFVGeom>::get();
     152              : 
     153              :         try{
     154              :                 UG_DLOG(DID_CONV_DIFF_FV1, 2, ">>OCT_DISC_DEBUG: " << "convection_diffusion_fv1.cpp: " << "prep_elem(): update(): "<< roid << std::endl);
     155            0 :                 geo.update(elem, vCornerCoords, &(this->subset_handler()));
     156            0 :         }UG_CATCH_THROW("ConvectionDiffusionFV1::prep_elem:"
     157              :                                                 " Cannot update Finite Volume Geometry.");
     158              : 
     159              : //      set local positions
     160              :         if(TFVGeom::usesHangingNodes)
     161              :         {
     162              :                 const int refDim = TElem::dim;
     163            0 :                 const MathVector<refDim>* vSCVFip = geo.scvf_local_ips();
     164              :                 const size_t numSCVFip = geo.num_scvf_ips();
     165              :                 const MathVector<refDim>* vSCVip = geo.scv_local_ips();
     166              :                 const size_t numSCVip = geo.num_scv_ips();
     167            0 :                 m_imDiffusion.template          set_local_ips<refDim>(vSCVFip,numSCVFip);
     168            0 :                 m_imVelocity.template           set_local_ips<refDim>(vSCVFip,numSCVFip);
     169            0 :                 m_imFlux.template                       set_local_ips<refDim>(vSCVFip,numSCVFip);
     170            0 :                 m_imSource.template             set_local_ips<refDim>(vSCVip,numSCVip);
     171            0 :                 m_imVectorSource.template       set_local_ips<refDim>(vSCVFip,numSCVFip);
     172            0 :                 m_imReactionRate.template       set_local_ips<refDim>(vSCVip,numSCVip);
     173            0 :                 m_imReaction.template           set_local_ips<refDim>(vSCVip,numSCVip);
     174            0 :                 m_imReactionRateExpl.template   set_local_ips<refDim>(vSCVip,numSCVip);
     175            0 :                 m_imReactionExpl.template       set_local_ips<refDim>(vSCVip,numSCVip);
     176            0 :                 m_imSourceExpl.template         set_local_ips<refDim>(vSCVip,numSCVip);
     177            0 :                 m_imMassScale.template          set_local_ips<refDim>(vSCVip,numSCVip);
     178            0 :                 m_imMass.template                       set_local_ips<refDim>(vSCVip,numSCVip);
     179              : 
     180            0 :                 if(m_spConvShape.valid())
     181            0 :                         if(!m_spConvShape->template set_geometry_type<TFVGeom>(geo))
     182            0 :                                 UG_THROW("ConvectionDiffusionFV1::prep_elem:"
     183              :                                                                 " Cannot init upwind for element type.");
     184              :         }
     185              : 
     186              :         //      set global positions
     187            0 :         const MathVector<dim>* vSCVFip = geo.scvf_global_ips();
     188              :         const size_t numSCVFip = geo.num_scvf_ips();
     189              :         const MathVector<dim>* vSCVip = geo.scv_global_ips();
     190              :         const size_t numSCVip = geo.num_scv_ips();
     191            0 :         m_imDiffusion.                  set_global_ips(vSCVFip, numSCVFip);
     192            0 :         m_imVelocity.                   set_global_ips(vSCVFip, numSCVFip);
     193            0 :         m_imFlux.                               set_global_ips(vSCVFip, numSCVFip);
     194            0 :         m_imSource.                             set_global_ips(vSCVip, numSCVip);
     195            0 :         m_imVectorSource.               set_global_ips(vSCVFip, numSCVFip);
     196            0 :         m_imReactionRate.               set_global_ips(vSCVip, numSCVip);
     197            0 :         m_imReactionRateExpl.   set_global_ips(vSCVip, numSCVip);
     198            0 :         m_imReactionExpl.               set_global_ips(vSCVip, numSCVip);
     199            0 :         m_imSourceExpl.                 set_global_ips(vSCVip, numSCVip);
     200            0 :         m_imReaction.                   set_global_ips(vSCVip, numSCVip);
     201            0 :         m_imMassScale.                  set_global_ips(vSCVip, numSCVip);
     202            0 :         m_imMass.                               set_global_ips(vSCVip, numSCVip);
     203            0 : }
     204              : 
     205              : template <class TVector>
     206              : static TVector CalculateCenter(GridObject* o, const TVector* coords)
     207              : {
     208              :         TVector v;
     209              :         VecSet(v, 0);
     210              : 
     211              :         size_t numCoords = 0;
     212              :         switch(o->base_object_id()){
     213              :                 case VERTEX: numCoords = 1; break;
     214              :                 case EDGE: numCoords = static_cast<Edge*>(o)->num_vertices(); break;
     215              :                 case FACE: numCoords = static_cast<Face*>(o)->num_vertices(); break;
     216              :                 case VOLUME: numCoords = static_cast<Volume*>(o)->num_vertices(); break;
     217              :                 default: UG_THROW("Unknown element type."); break;
     218              :         }
     219              : 
     220              :         for(size_t i = 0; i < numCoords; ++i)
     221              :                 VecAdd(v, v, coords[i]);
     222              : 
     223              :         if(numCoords > 0)
     224              :                 VecScale(v, v, 1. / (number)numCoords);
     225              : 
     226              :         return v;
     227              : }
     228              : 
     229              : template<typename TDomain>
     230              : template<typename TElem, typename TFVGeom>
     231              : void ConvectionDiffusionFV1<TDomain>::
     232              : add_sss_jac_elem
     233              : (
     234              :         LocalMatrix& J, ///< the matrix to update
     235              :         const LocalVector& u, ///< current solution
     236              :         GridObject* elem, ///< the element
     237              :         const TFVGeom& geo, ///< the FV geometry for that element
     238              :         size_t co, ///< index of the SCV
     239              :         number flux ///< flux through source/sink (premultiplied by the length for lines)
     240              : )
     241              : {
     242              : 
     243            0 :         if (flux < 0.0)
     244              :                 // sink
     245            0 :                 J(_C_, co, _C_, co) -= flux;
     246              : }
     247              : 
     248              : template<typename TDomain>
     249              : template<typename TElem, typename TFVGeom>
     250            0 : void ConvectionDiffusionFV1<TDomain>::
     251              : add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[])
     252              : {
     253              : // get finite volume geometry
     254            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
     255              : 
     256              : //      Diff. Tensor times Gradient
     257              :         MathVector<dim> Dgrad;
     258              : 
     259              : //      get conv shapes
     260            0 :         const IConvectionShapes<dim>& convShape = get_updated_conv_shapes(geo, false);
     261              : 
     262              : //      Diffusion and Velocity Term
     263            0 :         if(m_imDiffusion.data_given() || m_imVelocity.data_given())
     264              :         {
     265              :         //      loop Sub Control Volume Faces (SCVF)
     266            0 :                 for(size_t ip = 0; ip < geo.num_scvf(); ++ip)
     267              :                 {
     268              :                 //      get current SCVF
     269              :                         const typename TFVGeom::SCVF& scvf = geo.scvf(ip);
     270              : 
     271              :                 ////////////////////////////////////////////////////
     272              :                 // Diffusive Term
     273              :                 ////////////////////////////////////////////////////
     274            0 :                         if(m_imDiffusion.data_given())
     275              :                         {
     276              :                                 #ifdef UG_ENABLE_DEBUG_LOGS
     277              :                                 //      DID_CONV_DIFF_FV1
     278              :                                 number D_diff_flux_sum = 0.0;
     279              :                                 #endif
     280              : 
     281              :                         //      loop shape functions
     282            0 :                                 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
     283              :                                 {
     284              :                                 //      Compute Diffusion Tensor times Gradient
     285              :                                         MatVecMult(Dgrad, m_imDiffusion[ip], scvf.global_grad(sh));
     286              : 
     287              :                                 //      Compute flux at IP
     288              :                                         const number D_diff_flux = VecDot(Dgrad, scvf.normal());
     289              :                                         UG_DLOG(DID_CONV_DIFF_FV1, 2, ">>OCT_DISC_DEBUG: " << "convection_diffusion_fv1.cpp: " << "add_jac_A_elem(): " << "sh # "  << sh << " ; normalSize scvf # " << ip << ": " << VecLength(scvf.normal()) << "; \t from "<< scvf.from() << "; to " << scvf.to() << "; D_diff_flux: " << D_diff_flux << "; scvf.global_grad(sh): " << scvf.global_grad(sh) << std::endl);
     290              : 
     291              :                                 //      Add flux term to local matrix // HIER MATRIXINDIZES!!!
     292              :                                         UG_ASSERT((scvf.from() < J.num_row_dof(_C_)) && (scvf.to() < J.num_col_dof(_C_)),
     293              :                                                           "Bad local dof-index on element with object-id " << elem->base_object_id()
     294              :                                                           << " with center: " << CalculateCenter(elem, vCornerCoords));
     295              : 
     296            0 :                                         J(_C_, scvf.from(), _C_, sh) -= D_diff_flux;
     297            0 :                                         J(_C_, scvf.to()  , _C_, sh) += D_diff_flux;
     298              : 
     299              :                                         #ifdef UG_ENABLE_DEBUG_LOGS
     300              :                                         //      DID_CONV_DIFF_FV1
     301              :                                         D_diff_flux_sum += D_diff_flux;
     302              :                                         #endif
     303              :                                 }
     304              : 
     305              :                                 UG_DLOG(DID_CONV_DIFF_FV1, 2, "D_diff_flux_sum = " << D_diff_flux_sum << std::endl << std::endl);
     306              :                         }
     307              : 
     308              :                 ////////////////////////////////////////////////////
     309              :                 // Convective Term
     310              :                 ////////////////////////////////////////////////////
     311            0 :                         if(m_imVelocity.data_given())
     312              :                         {
     313              :                         //      Add Flux contribution
     314            0 :                                 for(size_t sh = 0; sh < convShape.num_sh(); ++sh)
     315              :                                 {
     316              :                                         const number D_conv_flux = convShape(ip, sh);
     317              : 
     318              :                                 //      Add flux term to local matrix
     319            0 :                                         J(_C_, scvf.from(), _C_, sh) += D_conv_flux;
     320            0 :                                         J(_C_, scvf.to(),   _C_, sh) -= D_conv_flux;
     321              :                                 }
     322              :                         }
     323              : 
     324              :                         // no explicit dependency on flux import
     325              :                 }
     326              :         }
     327              : 
     328              :         //UG_LOG("Local Matrix is: \n"<<J<<"\n");
     329              : 
     330              : ////////////////////////////////////////////////////
     331              : // Reaction Term (using lumping)
     332              : ////////////////////////////////////////////////////
     333              : 
     334            0 :         if(m_imReactionRate.data_given())
     335              :         {
     336              :         //      loop Sub Control Volume (SCV)
     337            0 :                 for(size_t ip = 0; ip < geo.num_scv(); ++ip)
     338              :                 {
     339              :                 //      get current SCV
     340              :                         const typename TFVGeom::SCV& scv = geo.scv(ip);
     341              :                         
     342              :                 //      get associated node
     343            0 :                         const int co = scv.node_id();
     344              :                         
     345              :                 //      Add to local matrix
     346            0 :                         J(_C_, co, _C_, co) += m_imReactionRate[ip] * scv.volume();
     347              :                 }
     348              :         }
     349              :         
     350              : //      reaction term does not explicitly depend on the associated unknown function
     351              : 
     352              : ////////////////////////////////
     353              : // Singular sources and sinks
     354              : ////////////////////////////////
     355              : 
     356            0 :         if (m_sss_mngr.valid () && (m_sss_mngr->num_points () != 0 || m_sss_mngr->num_lines () != 0))
     357              :     {
     358              :         typedef typename TDomain::position_accessor_type t_pos_accessor;
     359              :         typedef typename CDSingularSourcesAndSinks<dim>::template
     360              :                 point_iterator<TElem,t_pos_accessor,TFVGeom> t_pnt_sss_iter;
     361              :         typedef typename CDSingularSourcesAndSinks<dim>::template
     362              :                 line_iterator<TElem,t_pos_accessor,TFVGeom> t_lin_sss_iter;
     363              : 
     364            0 :                 t_pos_accessor& aaPos = this->domain()->position_accessor();
     365            0 :                 Grid& grid = (Grid&) *this->domain()->grid();
     366              :                 
     367            0 :                 for(size_t co = 0; co < geo.num_sh(); co++)
     368              :                 {
     369              :                         
     370              :                 //      point sources
     371            0 :                         for (t_pnt_sss_iter pnt (m_sss_mngr.get(), (TElem *) elem, grid, aaPos, geo, co);
     372            0 :                                 ! pnt.is_over (); ++pnt)
     373              :                         {
     374              :                                 FVPointSourceOrSink<dim, cd_point_sss_data<dim> > * pnt_sss = *pnt;
     375            0 :                                 if (! pnt_sss->marked_for (elem, co))
     376            0 :                                         continue;
     377              :                                 pnt_sss->compute (pnt_sss->position (), this->time (), -1); //TODO: set the subset id instead of -1
     378              :                                 this->template add_sss_jac_elem<TElem, TFVGeom> (J, u, elem, geo, co,
     379              :                                         pnt_sss->flux ());
     380              :                         }
     381              :                         
     382              :                 //      line sources
     383            0 :                         for (t_lin_sss_iter line (m_sss_mngr.get(), (TElem *) elem, grid, aaPos, geo, co);
     384            0 :                                 ! line.is_over (); ++line)
     385              :                         {
     386              :                                 FVLineSourceOrSink<dim, cd_line_sss_data<dim> > * line_sss = *line;
     387            0 :                                 number len = VecDistance (line.seg_start (), line.seg_end ());
     388              :                                 line_sss->compute (line.seg_start (), this->time (), -1); //TODO: set the subset id instead of -1
     389            0 :                                 this->template add_sss_jac_elem<TElem, TFVGeom> (J, u, elem, geo, co,
     390              :                                         line_sss->flux () * len);
     391              :                         }
     392              :                 }
     393              :     }
     394            0 : }
     395              : 
     396              : 
     397              : template<typename TDomain>
     398              : template<typename TElem, typename TFVGeom>
     399            0 : void ConvectionDiffusionFV1<TDomain>::
     400              : add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[])
     401              : {
     402              : //      get finite volume geometry
     403            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
     404              : 
     405            0 :         if(!m_imMassScale.data_given()) return;
     406              : 
     407              : //      loop Sub Control Volumes (SCV)
     408            0 :         for(size_t ip = 0; ip < geo.num_scv(); ++ip)
     409              :         {
     410              :         //      get current SCV
     411              :                 const typename TFVGeom::SCV& scv = geo.scv(ip);
     412              : 
     413              :         //      get associated node
     414            0 :                 const int co = scv.node_id();
     415              : 
     416              :         //      Add to local matrix
     417            0 :                 J(_C_, co, _C_, co) += scv.volume() * m_imMassScale[ip];
     418              :         }
     419              : 
     420              : //      m_imMass part does not explicitly depend on associated unknown function
     421              : }
     422              : 
     423              : 
     424              : template<typename TDomain>
     425              : template<typename TElem, typename TFVGeom>
     426              : void ConvectionDiffusionFV1<TDomain>::
     427              : add_sss_def_elem
     428              : (
     429              :         LocalVector& d, ///< the defect to update
     430              :         const LocalVector& u, ///< current solution
     431              :         GridObject* elem, ///< the element
     432              :         const TFVGeom& geo, ///< the FV geometry for that element
     433              :         size_t co, ///< index of the SCV
     434              :         number flux ///< flux through source/sink (premultiplied by the length for lines)
     435              : )
     436              : {
     437            0 :         if (flux > 0.0)
     438              :                 // source
     439            0 :                 d(_C_, co) -= flux;
     440              :         else
     441              :                 // sink
     442            0 :                 d(_C_, co) -= flux * u(_C_, co);
     443              : }
     444              : 
     445              : template<typename TDomain>
     446              : template<typename TElem, typename TFVGeom>
     447            0 : void ConvectionDiffusionFV1<TDomain>::
     448              : add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[])
     449              : {
     450              : //      get finite volume geometry
     451            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
     452              : 
     453              : //      get conv shapes
     454            0 :         const IConvectionShapes<dim>& convShape = get_updated_conv_shapes(geo, false);
     455              : 
     456            0 :         if(m_imDiffusion.data_given() || m_imVelocity.data_given() || m_imFlux.data_given())
     457              :         {
     458              :         //      loop Sub Control Volume Faces (SCVF)
     459            0 :                 for(size_t ip = 0; ip < geo.num_scvf(); ++ip)
     460              :                 {
     461              :                 //      get current SCVF
     462              :                         const typename TFVGeom::SCVF& scvf = geo.scvf(ip);
     463              : 
     464              :                 /////////////////////////////////////////////////////
     465              :                 // Diffusive Term
     466              :                 /////////////////////////////////////////////////////
     467            0 :                         if(m_imDiffusion.data_given())
     468              :                         {
     469              :                         //      to compute D \nabla c
     470              :                                 MathVector<dim> Dgrad_c, grad_c;
     471              : 
     472              :                         //      compute gradient and shape at ip
     473              :                                 VecSet(grad_c, 0.0);
     474            0 :                                 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
     475              :                                         VecScaleAppend(grad_c, u(_C_,sh), scvf.global_grad(sh));
     476              : 
     477              :                         //      scale by diffusion tensor
     478              :                                 MatVecMult(Dgrad_c, m_imDiffusion[ip], grad_c);
     479              : 
     480              :                         //      Compute flux
     481              :                                 const number diff_flux = VecDot(Dgrad_c, scvf.normal());
     482              : 
     483              :                         //      Add to local defect
     484            0 :                                 d(_C_, scvf.from()) -= diff_flux;
     485            0 :                                 d(_C_, scvf.to()  ) += diff_flux;
     486              :                         }
     487              : 
     488              :                 /////////////////////////////////////////////////////
     489              :                 // Convective Term
     490              :                 /////////////////////////////////////////////////////
     491            0 :                         if(m_imVelocity.data_given())
     492              :                         {
     493              :                         //      sum up convective flux using convection shapes
     494              :                                 number conv_flux = 0.0;
     495            0 :                                 for(size_t sh = 0; sh < convShape.num_sh(); ++sh)
     496            0 :                                         conv_flux += u(_C_, sh) * convShape(ip, sh);
     497              : 
     498              :                         //  add to local defect
     499            0 :                                 d(_C_, scvf.from()) += conv_flux;
     500            0 :                                 d(_C_, scvf.to()  ) -= conv_flux;
     501              :                         }
     502              : 
     503              :                 /////////////////////////////////////////////////////
     504              :                 // Flux Term
     505              :                 /////////////////////////////////////////////////////
     506            0 :                         if(m_imFlux.data_given())
     507              :                         {
     508              :                         //      sum up flux
     509              :                                 const number flux = VecDot(m_imFlux[ip], scvf.normal());
     510              : 
     511              :                         //  add to local defect
     512            0 :                                 d(_C_, scvf.from()) += flux;
     513            0 :                                 d(_C_, scvf.to()  ) -= flux;
     514              :                         }
     515              : 
     516              :                 }
     517              :         }
     518              : 
     519              : //      reaction rate
     520            0 :         if(m_imReactionRate.data_given())
     521              :         {
     522              :         //      loop Sub Control Volumes (SCV)
     523            0 :                 for(size_t ip = 0; ip < geo.num_scv(); ++ip)
     524              :                 {
     525              :                 //      get current SCV
     526              :                         const typename TFVGeom::SCV& scv = geo.scv(ip);
     527              : 
     528              :                 //      get associated node
     529            0 :                         const int co = scv.node_id();
     530              : 
     531              :                 //      Add to local defect
     532            0 :                         d(_C_, co) += u(_C_, co) * m_imReactionRate[ip] * scv.volume();
     533              :                 }
     534              :         }
     535              : 
     536              : //      reaction term
     537            0 :         if(m_imReaction.data_given())
     538              :         {
     539              :         //      loop Sub Control Volumes (SCV)
     540            0 :                 for(size_t ip = 0; ip < geo.num_scv(); ++ip)
     541              :                 {
     542              :                 //      get current SCV
     543              :                         const typename TFVGeom::SCV& scv = geo.scv(ip);
     544              : 
     545              :                 //      get associated node
     546            0 :                         const int co = scv.node_id();
     547              : 
     548              :                 //      Add to local defect
     549            0 :                         d(_C_, co) += m_imReaction[ip] * scv.volume();
     550              :                 }
     551              :         }
     552              : 
     553              : ////////////////////////////////
     554              : // Singular sources and sinks
     555              : ////////////////////////////////
     556              : 
     557            0 :     if (m_sss_mngr.valid () && (m_sss_mngr->num_points () != 0 || m_sss_mngr->num_lines () != 0))
     558              :     {
     559              :         typedef typename TDomain::position_accessor_type t_pos_accessor;
     560              :         typedef typename CDSingularSourcesAndSinks<dim>::template
     561              :                 point_iterator<TElem,t_pos_accessor,TFVGeom> t_pnt_sss_iter;
     562              :         typedef typename CDSingularSourcesAndSinks<dim>::template
     563              :                 line_iterator<TElem,t_pos_accessor,TFVGeom> t_lin_sss_iter;
     564              :         
     565            0 :                 t_pos_accessor& aaPos = this->domain()->position_accessor();
     566            0 :                 Grid& grid = (Grid&) *this->domain()->grid();
     567              :                 
     568              :                 //for(size_t i = 0; i < geo.num_scv(); i++)
     569            0 :                 for(size_t co = 0; co < geo.num_sh(); co++)
     570              :                 {
     571              :                         
     572              :                 //      point sources
     573            0 :                 for (t_pnt_sss_iter pnt (m_sss_mngr.get(), (TElem *) elem, grid, aaPos, geo, co);
     574            0 :                                 ! pnt.is_over (); ++pnt)
     575              :                         {
     576              :                                 FVPointSourceOrSink<dim, cd_point_sss_data<dim> > * pnt_sss = *pnt;
     577            0 :                                 if (! pnt_sss->marked_for (elem, co))
     578            0 :                                         continue;
     579              :                                 pnt_sss->compute (pnt_sss->position (), this->time (), -1); //TODO: set the subset id instead of -1
     580              :                                 this->template add_sss_def_elem<TElem, TFVGeom> (d, u, elem, geo, co,
     581              :                                         pnt_sss->flux ());
     582              :                         }
     583              :                         
     584              :                 //      line sources
     585            0 :                         for (t_lin_sss_iter line (m_sss_mngr.get(), (TElem *) elem, grid, aaPos, geo, co);
     586            0 :                                 ! line.is_over (); ++line)
     587              :                         {
     588              :                                 FVLineSourceOrSink<dim, cd_line_sss_data<dim> > * line_sss = *line;
     589            0 :                                 number len = VecDistance (line.seg_start (), line.seg_end ());
     590              :                                 line_sss->compute (line.seg_start (), this->time (), -1); //TODO: set the subset id instead of -1
     591            0 :                                 this->template add_sss_def_elem<TElem, TFVGeom> (d, u, elem, geo, co,
     592              :                                         line_sss->flux () * len);
     593              :                         }
     594              :                 }
     595              :     }
     596            0 : }
     597              : 
     598              : template<typename TDomain>
     599              : template<typename TElem, typename TFVGeom>
     600            0 : void ConvectionDiffusionFV1<TDomain>::
     601              : add_def_A_expl_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[])
     602              : {
     603              : //      get finite volume geometry
     604            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
     605              : 
     606              : //      reaction rate
     607            0 :         if(m_imReactionRateExpl.data_given())
     608              :         {
     609              :         //      loop Sub Control Volumes (SCV)
     610            0 :                 for(size_t ip = 0; ip < geo.num_scv(); ++ip)
     611              :                 {
     612              :                 //      get current SCV
     613              :                         const typename TFVGeom::SCV& scv = geo.scv(ip);
     614              : 
     615              :                 //      get associated node
     616            0 :                         const int co = scv.node_id();
     617              : 
     618              :                 //      Add to local defect
     619            0 :                         d(_C_, co) += u(_C_, co) * m_imReactionRateExpl[ip] * scv.volume();
     620              :                 }
     621              :         }
     622              : 
     623              : //      reaction
     624            0 :         if(m_imReactionExpl.data_given())
     625              :         {
     626              :         //      loop Sub Control Volumes (SCV)
     627            0 :                 for(size_t ip = 0; ip < geo.num_scv(); ++ip)
     628              :                 {
     629              :                 //      get current SCV
     630              :                         const typename TFVGeom::SCV& scv = geo.scv(ip);
     631              : 
     632              :                 //      get associated node
     633            0 :                         const int co = scv.node_id();
     634              : 
     635              :                 //      Add to local defect
     636            0 :                         d(_C_, co) += m_imReactionExpl[ip] * scv.volume();
     637              :                 }
     638              :         }
     639              : 
     640            0 :         if(m_imSourceExpl.data_given())
     641              :         {
     642              :                 //      loop Sub Control Volumes (SCV)
     643            0 :                 for(size_t ip = 0; ip < geo.num_scv(); ++ip)
     644              :                 {
     645              :                         //      get current SCV
     646              :                         const typename TFVGeom::SCV& scv = geo.scv(ip);
     647              : 
     648              :                         //      get associated node
     649            0 :                         const int co = scv.node_id();
     650              : 
     651              :                         //      Add to local rhs
     652            0 :                         d(_C_, co) -= m_imSourceExpl[ip] * scv.volume();
     653              :                 }
     654              :         }
     655            0 : }
     656              : 
     657              : template<typename TDomain>
     658              : template<typename TElem, typename TFVGeom>
     659            0 : void ConvectionDiffusionFV1<TDomain>::
     660              : add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[])
     661              : {
     662              : //      get finite volume geometry
     663            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
     664              : 
     665            0 :         if(!m_imMassScale.data_given() && !m_imMass.data_given()) return;
     666              : 
     667              : //      loop Sub Control Volumes (SCV)
     668            0 :         for(size_t ip = 0; ip < geo.num_scv(); ++ip)
     669              :         {
     670              :         //      get current SCV
     671              :                 const typename TFVGeom::SCV& scv = geo.scv(ip);
     672              : 
     673              :         //      get associated node
     674            0 :                 const int co = scv.node_id();
     675              : 
     676              :         //      mass value
     677              :                 number val = 0.0;
     678              : 
     679              :         //      multiply by scaling
     680            0 :                 if(m_imMassScale.data_given())
     681            0 :                         val += m_imMassScale[ip] * u(_C_, co);
     682              : 
     683              :         //      add mass
     684            0 :                 if(m_imMass.data_given())
     685            0 :                         val += m_imMass[ip];
     686              : 
     687              :         //      Add to local defect
     688            0 :                 d(_C_, co) += val * scv.volume();
     689              :         }
     690              : }
     691              : 
     692              : 
     693              : template<typename TDomain>
     694              : template<typename TElem, typename TFVGeom>
     695            0 : void ConvectionDiffusionFV1<TDomain>::
     696              : add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector<dim> vCornerCoords[])
     697              : {
     698              :         // get finite volume geometry
     699            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
     700              : 
     701              :         // loop Sub Control Volumes (SCV)
     702            0 :         if ( m_imSource.data_given() ) {
     703            0 :                 for ( size_t ip = 0; ip < geo.num_scv(); ++ip ) {
     704              :                         // get current SCV
     705              :                         const typename TFVGeom::SCV& scv = geo.scv( ip );
     706              : 
     707              :                         // get associated node
     708            0 :                         const int co = scv.node_id();
     709              : 
     710              :                         // Add to local rhs
     711            0 :                         d(_C_, co) += m_imSource[ip] * scv.volume();
     712              :                         //UG_LOG("d(_C_, co) = " << d(_C_, co) << "; \t ip " << ip << "; \t co " << co << "; \t scv_vol " << scv.volume() << "; \t m_imSource[ip] " << m_imSource[ip] << std::endl);
     713              :                 }
     714              :         }
     715              : 
     716              :         // loop Sub Control Volumes (SCVF)
     717            0 :         if ( m_imVectorSource.data_given() ) {
     718            0 :                 for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) {
     719              :                         // get current SCVF
     720              :                         const typename TFVGeom::SCVF& scvf = geo.scvf( ip );
     721              : 
     722              :                         // Add to local rhs
     723              :                         number flux = VecDot(m_imVectorSource[ip], scvf.normal());
     724            0 :                         d(_C_, scvf.from()) -= flux;
     725            0 :                         d(_C_, scvf.to()  ) += flux;
     726              :                 }
     727              :         }
     728            0 : }
     729              : 
     730              : 
     731              : // ////////////////////////////////
     732              : //   error estimation (begin)   ///
     733              : 
     734              : //      prepares the loop over all elements of one type for the computation of the error estimator
     735              : template<typename TDomain>
     736              : template<typename TElem, typename TFVGeom>
     737            0 : void ConvectionDiffusionFV1<TDomain>::
     738              : prep_err_est_elem_loop(const ReferenceObjectID roid, const int si)
     739              : {
     740              :         //      get the error estimator data object and check that it is of the right type
     741              :         //      we check this at this point in order to be able to dispense with this check later on
     742              :         //      (i.e. in prep_err_est_elem and compute_err_est_A_elem())
     743            0 :         if (this->m_spErrEstData.get() == NULL)
     744              :         {
     745            0 :                 UG_THROW("No ErrEstData object has been given to this ElemDisc!");
     746              :         }
     747              : 
     748            0 :         err_est_type* err_est_data = dynamic_cast<err_est_type*>(this->m_spErrEstData.get());
     749              : 
     750            0 :         if (!err_est_data)
     751              :         {
     752            0 :                 UG_THROW("Dynamic cast to SideAndElemErrEstData failed."
     753              :                                 << std::endl << "Make sure you handed the correct type of ErrEstData to this discretization.");
     754              :         }
     755              : 
     756              : 
     757              : //      check that upwind has been set
     758            0 :         if (m_spConvShape.invalid())
     759            0 :                 UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: "
     760              :                                  "Upwind has not been set.");
     761              : 
     762              : //      set local positions
     763              :         if (!TFVGeom::usesHangingNodes)
     764              :         {
     765              :                 static const int refDim = TElem::dim;
     766              : 
     767              :                 // get local IPs
     768              :                 size_t numSideIPs, numElemIPs;
     769              :                 const MathVector<refDim>* sideIPs;
     770              :                 const MathVector<refDim>* elemIPs;
     771              :                 try
     772              :                 {
     773              :                         numSideIPs = err_est_data->num_all_side_ips(roid);
     774            0 :                         numElemIPs = err_est_data->num_elem_ips(roid);
     775            0 :                         sideIPs = err_est_data->template side_local_ips<refDim>(roid);
     776            0 :                         elemIPs = err_est_data->template elem_local_ips<refDim>(roid);
     777              : 
     778            0 :                         if (!sideIPs || !elemIPs) return;       // are NULL if TElem is not of the same dim as TDomain
     779              :                 }
     780            0 :                 UG_CATCH_THROW("Integration points for error estimator cannot be set.");
     781              : 
     782              :                 // set local IPs in imports
     783            0 :                 m_imDiffusion.template          set_local_ips<refDim>(sideIPs, numSideIPs, false);
     784            0 :                 m_imVelocity.template           set_local_ips<refDim>(sideIPs, numSideIPs, false);
     785            0 :                 m_imFlux.template                       set_local_ips<refDim>(sideIPs, numSideIPs, false);
     786            0 :                 m_imSource.template             set_local_ips<refDim>(elemIPs, numElemIPs, false);
     787            0 :                 m_imVectorSource.template       set_local_ips<refDim>(sideIPs, numSideIPs, false);
     788            0 :                 m_imReactionRate.template       set_local_ips<refDim>(elemIPs, numElemIPs, false);
     789            0 :                 m_imReaction.template           set_local_ips<refDim>(elemIPs, numElemIPs, false);
     790            0 :                 m_imMassScale.template          set_local_ips<refDim>(elemIPs, numElemIPs, false);
     791            0 :                 m_imMass.template                       set_local_ips<refDim>(elemIPs, numElemIPs, false);
     792              : 
     793              :                 //      init upwind for element type
     794            0 :                 TFVGeom& geo = GeomProvider<TFVGeom>::get();
     795            0 :                 if (!m_spConvShape->template set_geometry_type<TFVGeom>(geo))
     796            0 :                         UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: "
     797              :                                          "Cannot init upwind for element type.");
     798              : 
     799              :                 // store values of shape functions in local IPs
     800              :                 LagrangeP1<typename reference_element_traits<TElem>::reference_element_type> trialSpace
     801            0 :                                         = Provider<LagrangeP1<typename reference_element_traits<TElem>::reference_element_type> >::get();
     802              : 
     803            0 :                 m_shapeValues.resize(numElemIPs, numSideIPs, trialSpace.num_sh());
     804            0 :                 for (size_t ip = 0; ip < numElemIPs; ip++)
     805            0 :                         trialSpace.shapes(m_shapeValues.shapesAtElemIP(ip), elemIPs[ip]);
     806            0 :                 for (size_t ip = 0; ip < numSideIPs; ip++)
     807            0 :                         trialSpace.shapes(m_shapeValues.shapesAtSideIP(ip), sideIPs[ip]);
     808              :         }
     809              : }
     810              : 
     811              : template<typename TDomain>
     812              : template<typename TElem, typename TFVGeom>
     813            0 : void ConvectionDiffusionFV1<TDomain>::
     814              : prep_err_est_elem(const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[])
     815              : {
     816            0 :         err_est_type* err_est_data = dynamic_cast<err_est_type*>(this->m_spErrEstData.get());
     817              : 
     818              : //      update geometry for this element
     819            0 :         static TFVGeom& geo = GeomProvider<TFVGeom>::get();
     820              :         try
     821              :         {
     822            0 :                 geo.update(elem, vCornerCoords, &(this->subset_handler()));
     823              :         }
     824            0 :         UG_CATCH_THROW("ConvectionDiffusionFV1::prep_err_est_elem: Cannot update Finite Volume Geometry.");
     825              : 
     826              : //      roid
     827            0 :         ReferenceObjectID roid = elem->reference_object_id();
     828              : 
     829              : //      set local positions
     830              :         if (TFVGeom::usesHangingNodes)
     831              :         {
     832              :                 static const int refDim = TElem::dim;
     833              : 
     834              :                 size_t numSideIPs, numElemIPs;
     835              :                 const MathVector<refDim>* sideIPs;
     836              :                 const MathVector<refDim>* elemIPs;
     837              :                 try
     838              :                 {
     839              :                         numSideIPs = err_est_data->num_all_side_ips(roid);
     840            0 :                         numElemIPs = err_est_data->num_elem_ips(roid);
     841            0 :                         sideIPs = err_est_data->template side_local_ips<refDim>(roid);
     842            0 :                         elemIPs = err_est_data->template elem_local_ips<refDim>(roid);
     843              : 
     844            0 :                         if (!sideIPs || !elemIPs) return;       // are NULL if TElem is not of the same dim as TDomain
     845              :                 }
     846            0 :                 UG_CATCH_THROW("Integration points for error estimator cannot be set.");
     847              : 
     848            0 :                 m_imDiffusion.template          set_local_ips<refDim>(sideIPs, numSideIPs);
     849            0 :                 m_imVelocity.template           set_local_ips<refDim>(sideIPs, numSideIPs);
     850            0 :                 m_imFlux.template                       set_local_ips<refDim>(sideIPs, numSideIPs);
     851            0 :                 m_imSource.template             set_local_ips<refDim>(elemIPs, numElemIPs);
     852            0 :                 m_imVectorSource.template       set_local_ips<refDim>(sideIPs, numSideIPs);
     853            0 :                 m_imReactionRate.template       set_local_ips<refDim>(elemIPs, numElemIPs);
     854            0 :                 m_imReaction.template           set_local_ips<refDim>(elemIPs, numElemIPs);
     855            0 :                 m_imMassScale.template          set_local_ips<refDim>(elemIPs, numElemIPs);
     856            0 :                 m_imMass.template                       set_local_ips<refDim>(elemIPs, numElemIPs);
     857              : 
     858              :                 //      init upwind for element type
     859            0 :                 TFVGeom& geo = GeomProvider<TFVGeom>::get();
     860            0 :                 if (!m_spConvShape->template set_geometry_type<TFVGeom>(geo))
     861            0 :                         UG_THROW("ConvectionDiffusionFV1::prep_err_est_elem_loop: "
     862              :                                          "Cannot init upwind for element type.");
     863              : 
     864              :                 // store values of shape functions in local IPs
     865              :                 LagrangeP1<typename reference_element_traits<TElem>::reference_element_type> trialSpace
     866            0 :                                         = Provider<LagrangeP1<typename reference_element_traits<TElem>::reference_element_type> >::get();
     867              : 
     868            0 :                 m_shapeValues.resize(numElemIPs, numSideIPs, trialSpace.num_sh());
     869            0 :                 for (size_t ip = 0; ip < numElemIPs; ip++)
     870            0 :                         trialSpace.shapes(m_shapeValues.shapesAtElemIP(ip), elemIPs[ip]);
     871            0 :                 for (size_t ip = 0; ip < numSideIPs; ip++)
     872            0 :                         trialSpace.shapes(m_shapeValues.shapesAtSideIP(ip), sideIPs[ip]);
     873              :         }
     874              : 
     875              : //      set global positions
     876              :         size_t numSideIPs, numElemIPs;
     877              :         const MathVector<dim>* sideIPs;
     878              :         const MathVector<dim>* elemIPs;
     879              : 
     880              :         try
     881              :         {
     882              :                 numSideIPs = err_est_data->num_all_side_ips(roid);
     883            0 :                 numElemIPs = err_est_data->num_elem_ips(roid);
     884              : 
     885            0 :                 sideIPs = err_est_data->all_side_global_ips(elem, vCornerCoords);
     886            0 :                 elemIPs = err_est_data->elem_global_ips(elem, vCornerCoords);
     887              :         }
     888            0 :         UG_CATCH_THROW("Global integration points for error estimator cannot be set.");
     889              : 
     890            0 :         m_imDiffusion.                  set_global_ips(&sideIPs[0], numSideIPs);
     891            0 :         m_imVelocity.                   set_global_ips(&sideIPs[0], numSideIPs);
     892            0 :         m_imFlux.                               set_global_ips(&sideIPs[0], numSideIPs);
     893            0 :         m_imSource.                             set_global_ips(&elemIPs[0], numElemIPs);
     894            0 :         m_imVectorSource.               set_global_ips(&sideIPs[0], numSideIPs);
     895            0 :         m_imReactionRate.               set_global_ips(&elemIPs[0], numElemIPs);
     896            0 :         m_imReaction.                   set_global_ips(&elemIPs[0], numElemIPs);
     897            0 :         m_imMassScale.                  set_global_ips(&elemIPs[0], numElemIPs);
     898            0 :         m_imMass.                               set_global_ips(&elemIPs[0], numElemIPs);
     899              : }
     900              : 
     901              : //      computes the error estimator contribution (stiffness part) for one element
     902              : template<typename TDomain>
     903              : template<typename TElem, typename TFVGeom>
     904            0 : void ConvectionDiffusionFV1<TDomain>::
     905              : compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[], const number& scale)
     906              : {
     907              :         typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
     908              : 
     909            0 :         err_est_type* err_est_data = dynamic_cast<err_est_type*>(this->m_spErrEstData.get());
     910              : 
     911            0 :         if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");}
     912            0 :         MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid());
     913              : 
     914              : //      request geometry
     915            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
     916              : 
     917              : 
     918              : // SIDE TERMS //
     919              : 
     920              : //      get the sides of the element
     921              :         //      We have to cast elem to a pointer of type SideAndElemErrEstData::elem_type
     922              :         //      for the SideAndElemErrEstData::operator() to work properly.
     923              :         //      This cannot generally be achieved by casting to TElem*, since this method is also registered for
     924              :         //      lower-dimensional types TElem, and must therefore be compilable, even if it is never EVER to be executed.
     925              :         //      The way we achieve this here, is by calling associated_elements_sorted() which has an implementation for
     926              :         //      all possible types. Whatever comes out of it is of course complete nonsense if (and only if)
     927              :         //      SideAndElemErrEstData::elem_type != TElem. To be on the safe side, we throw an error if the number of
     928              :         //      entries in the list is not as it should be.
     929              : 
     930              :         typename MultiGrid::traits<typename SideAndElemErrEstData<TDomain>::side_type>::secure_container side_list;
     931            0 :         pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem);
     932            0 :         if (side_list.size() != (size_t) ref_elem_type::numSides)
     933            0 :                 UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'");
     934              : 
     935              : //      some help variables
     936              :         MathVector<dim> fluxDensity, gradC, normal;
     937              : 
     938              :         // FIXME: The computation of the gradient has to be reworked.
     939              :         // In the case of P1 shape functions, it is valid. For Q1 shape functions, however,
     940              :         // the gradient is not constant (but bilinear) on the element - and along the sides.
     941              :         // We cannot use the FVGeom here. Instead, we need to calculate the gradient in each IP!
     942              : 
     943              :         // calculate grad u (take grad from first scvf ip (grad u is constant on the entire element))
     944              : /*      if (geo.num_scvf() < 1) {UG_THROW("Element has no SCVFs!");}
     945              :         const typename TFVGeom::SCVF& scvf = geo.scvf(0);
     946              : 
     947              :         VecSet(gradC, 0.0);
     948              :         for (size_t j=0; j<m_shapeValues.num_sh(); j++)
     949              :                 VecScaleAppend(gradC, u(_C_,j), scvf.global_grad(j));*/
     950              : 
     951              :         // calculate grad u as average (over scvf)
     952              :         VecSet(gradC, 0.0);
     953            0 :         for(size_t ii = 0; ii < geo.num_scvf(); ++ii)
     954              :         {
     955              :                 const typename TFVGeom::SCVF& scvf = geo.scvf(ii);
     956            0 :                 for (size_t j=0; j<m_shapeValues.num_sh(); j++)
     957              :                                 VecScaleAppend(gradC, u(_C_,j), scvf.global_grad(j));
     958              :         }
     959            0 :         VecScale(gradC, gradC, (1.0/geo.num_scvf()));
     960              : 
     961              :         /*VecSet(gradC, 0.0);
     962              :         for(size_t ii = 0; ii < geo.num_scv(); ++ii)
     963              :         {
     964              :                 const typename TFVGeom::SCV& scv = geo.scv(ii);
     965              :                         for (size_t j=0; j<m_shapeValues.num_sh(); j++)
     966              :                                         VecScaleAppend(gradC, u(_C_,j), scv.global_grad(j));
     967              :         }
     968              :         VecScale(gradC, gradC, (1.0/geo.num_scvf()));
     969              : */
     970              : 
     971              : // calculate flux through the sides
     972              :         size_t passedIPs = 0;
     973            0 :         for (size_t side=0; side < (size_t) ref_elem_type::numSides; side++)
     974              :         {
     975              :                 // normal on side
     976            0 :                 SideNormal<ref_elem_type,dim>(normal, side, vCornerCoords);
     977            0 :                 VecNormalize(normal, normal);
     978              : 
     979              :                 try
     980              :                 {
     981            0 :                         for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++)
     982              :                         {
     983            0 :                                 size_t ip = passedIPs + sip;
     984              : 
     985              :                                 VecSet(fluxDensity, 0.0);
     986              : 
     987              :                         // diffusion //
     988            0 :                                 if (m_imDiffusion.data_given())
     989              :                                         MatVecScaleMultAppend(fluxDensity, -1.0, m_imDiffusion[ip], gradC);
     990              : 
     991              :                         // convection //
     992            0 :                                 if (m_imVelocity.data_given())
     993              :                                 {
     994              :                                         number val = 0.0;
     995            0 :                                         for (size_t sh = 0; sh < m_shapeValues.num_sh(); sh++)
     996            0 :                                                 val += u(_C_,sh) * m_shapeValues.shapeAtSideIP(sh,sip);
     997              : 
     998              :                                         VecScaleAppend(fluxDensity, val, m_imVelocity[ip]);
     999              :                                 }
    1000              : 
    1001              :                         // general flux //
    1002            0 :                                 if (m_imFlux.data_given())
    1003              :                                         VecAppend(fluxDensity, m_imFlux[ip]);
    1004              : 
    1005            0 :                                 (*err_est_data)(side_list[side],sip) += scale * VecDot(fluxDensity, normal);
    1006              :                         }
    1007              : 
    1008            0 :                         passedIPs += err_est_data->num_side_ips(side_list[side]);
    1009              :                 }
    1010            0 :                 UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl
    1011              :                                 << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData.");
    1012              :         }
    1013              : 
    1014              : // VOLUME TERMS //
    1015              : 
    1016              :         typename MultiGrid::traits<typename SideAndElemErrEstData<TDomain>::elem_type>::secure_container elem_list;
    1017              :         pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem);
    1018            0 :         if (elem_list.size() != 1)
    1019            0 :                 UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'");
    1020              : 
    1021              :         try
    1022              :         {
    1023            0 :                 for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++)
    1024              :                 {
    1025              :                         number total = 0.0;
    1026              : 
    1027              :                 // diffusion // TODO ONLY FOR (PIECEWISE) CONSTANT DIFFUSION TENSOR SO FAR!
    1028              :                 // div(D*grad(c))
    1029              :                 // nothing to do, as c is piecewise linear and div(D*grad(c)) disappears
    1030              :                 // if D is diagonal and c bilinear, this should also vanish (confirm this!)
    1031              : 
    1032              :                 // convection // TODO ONLY FOR (PIECEWISE) CONSTANT OR DIVERGENCE-FREE
    1033              :                                           //      VELOCITY FIELDS SO FAR!
    1034              :                 // div(v*c) = div(v)*c + v*grad(c) -- gradC has been calculated above
    1035            0 :                         if (m_imVelocity.data_given())
    1036            0 :                                 total += VecDot(m_imVelocity[ip], gradC);
    1037              : 
    1038              :                 // general flux // TODO ONLY FOR DIVERGENCE-FREE FLUX FIELD SO FAR!
    1039              :                 // nothing to do
    1040              : 
    1041              :                 // reaction //
    1042            0 :                         if (m_imReactionRate.data_given())
    1043              :                         {
    1044              :                                 number val = 0.0;
    1045            0 :                                 for (size_t sh = 0; sh < geo.num_sh(); sh++)
    1046            0 :                                         val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip);
    1047              : 
    1048            0 :                                 total += m_imReactionRate[ip] * val;
    1049              :                         }
    1050              : 
    1051            0 :                         if (m_imReaction.data_given())
    1052              :                         {
    1053            0 :                                 total += m_imReaction[ip];
    1054              :                         }
    1055              : 
    1056            0 :                         (*err_est_data)(elem_list[0],ip) += scale * total;
    1057              :                 }
    1058              :         }
    1059            0 :         UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl
    1060              :                         << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData.");
    1061            0 : }
    1062              : 
    1063              : //      computes the error estimator contribution (mass part) for one element
    1064              : template<typename TDomain>
    1065              : template<typename TElem, typename TFVGeom>
    1066            0 : void ConvectionDiffusionFV1<TDomain>::
    1067              : compute_err_est_M_elem(const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[], const number& scale)
    1068              : {
    1069              : // note: mass parts only enter volume term
    1070              : 
    1071            0 :         err_est_type* err_est_data = dynamic_cast<err_est_type*>(this->m_spErrEstData.get());
    1072              : 
    1073            0 :         if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");}
    1074            0 :         MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid());
    1075              : 
    1076              :         typename MultiGrid::traits<typename SideAndElemErrEstData<TDomain>::elem_type>::secure_container elem_list;
    1077            0 :         pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem);
    1078            0 :         if (elem_list.size() != 1)
    1079            0 :                 UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'");
    1080              : 
    1081              : //      request geometry
    1082            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
    1083              : 
    1084              : //      loop integration points
    1085              :         try
    1086              :         {
    1087            0 :                 for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++)
    1088              :                 {
    1089              :                         number total = 0.0;
    1090              : 
    1091              :                 // mass scale //
    1092            0 :                         if (m_imMassScale.data_given())
    1093              :                         {
    1094              :                                 number val = 0.0;
    1095            0 :                                 for (size_t sh = 0; sh < geo.num_sh(); sh++)
    1096            0 :                                         val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip);
    1097              : 
    1098            0 :                                 total += m_imMassScale[ip] * val;
    1099              :                         }
    1100              : 
    1101              :                 // mass //
    1102            0 :                         if (m_imMass.data_given())
    1103              :                         {
    1104            0 :                                 total += m_imMass[ip];
    1105              :                         }
    1106              : 
    1107            0 :                         (*err_est_data)(elem_list[0],ip) += scale * total;
    1108              :                 }
    1109              :         }
    1110            0 :         UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl
    1111              :                         << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData.");
    1112            0 : }
    1113              : 
    1114              : //      computes the error estimator contribution (rhs part) for one element
    1115              : template<typename TDomain>
    1116              : template<typename TElem, typename TFVGeom>
    1117            0 : void ConvectionDiffusionFV1<TDomain>::
    1118              : compute_err_est_rhs_elem(GridObject* elem, const MathVector<dim> vCornerCoords[], const number& scale)
    1119              : {
    1120              :         typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type;
    1121              : 
    1122            0 :         err_est_type* err_est_data = dynamic_cast<err_est_type*>(this->m_spErrEstData.get());
    1123              : 
    1124            0 :         if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");}
    1125            0 :         MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid());
    1126              : 
    1127              : // SIDE TERMS //
    1128              : 
    1129              : //      get the sides of the element
    1130              :         typename MultiGrid::traits<typename SideAndElemErrEstData<TDomain>::side_type>::secure_container side_list;
    1131            0 :         pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem);
    1132            0 :         if (side_list.size() != (size_t) ref_elem_type::numSides)
    1133            0 :                 UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'");
    1134              : 
    1135              : // loop sides
    1136              :         size_t passedIPs = 0;
    1137            0 :         for (size_t side = 0; side < (size_t) ref_elem_type::numSides; side++)
    1138              :         {
    1139              :                 // normal on side
    1140              :                 MathVector<dim> normal;
    1141            0 :                 SideNormal<ref_elem_type,dim>(normal, side, vCornerCoords);
    1142            0 :                 VecNormalize(normal, normal);
    1143              : 
    1144              :                 try
    1145              :                 {
    1146            0 :                         for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++)
    1147              :                         {
    1148            0 :                                 size_t ip = passedIPs + sip;
    1149              : 
    1150              :                         // vector source //
    1151            0 :                                 if (m_imVectorSource.data_given())
    1152            0 :                                         (*err_est_data)(side_list[side],sip) += scale * VecDot(m_imVectorSource[ip], normal);
    1153              :                         }
    1154              : 
    1155            0 :                         passedIPs += err_est_data->num_side_ips(side_list[side]);
    1156              :                 }
    1157            0 :                 UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl
    1158              :                                 << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData.");
    1159              :         }
    1160              : 
    1161              : // VOLUME TERMS //
    1162              : 
    1163            0 :         if (!m_imSource.data_given()) return;
    1164              : 
    1165              :         typename MultiGrid::traits<typename SideAndElemErrEstData<TDomain>::elem_type>::secure_container elem_list;
    1166              :         pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem);
    1167            0 :         if (elem_list.size() != 1)
    1168            0 :                 UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFV1::compute_err_est_elem'");
    1169              : 
    1170              : // source //
    1171              :         try
    1172              :         {
    1173            0 :                 for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++)
    1174            0 :                         (*err_est_data)(elem_list[0],ip) += scale * m_imSource[ip];
    1175              :         }
    1176            0 :         UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl
    1177              :                         << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData.");
    1178              : }
    1179              : 
    1180              : //      postprocesses the loop over all elements of one type in the computation of the error estimator
    1181              : template<typename TDomain>
    1182              : template<typename TElem, typename TFVGeom>
    1183            0 : void ConvectionDiffusionFV1<TDomain>::
    1184              : fsh_err_est_elem_loop()
    1185              : {
    1186              : //      finish the element loop in the same way as the actual discretization
    1187              :         this->template fsh_elem_loop<TElem, TFVGeom> ();
    1188            0 : };
    1189              : 
    1190              : //    error estimation (end)     ///
    1191              : // /////////////////////////////////
    1192              : 
    1193              : //      computes the linearized defect w.r.t to the velocity
    1194              : template<typename TDomain>
    1195              : template <typename TElem, typename TFVGeom>
    1196            0 : void ConvectionDiffusionFV1<TDomain>::
    1197              : lin_def_velocity(const LocalVector& u,
    1198              :                  std::vector<std::vector<MathVector<dim> > > vvvLinDef[],
    1199              :                  const size_t nip)
    1200              : {
    1201              : //      get finite volume geometry
    1202            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
    1203              : 
    1204              : //      get conv shapes
    1205            0 :         const IConvectionShapes<dim>& convShape = get_updated_conv_shapes(geo, true);
    1206              : 
    1207              : //      reset the values for the linearized defect
    1208            0 :         for(size_t ip = 0; ip < nip; ++ip)
    1209            0 :                 for(size_t c = 0; c < vvvLinDef[ip].size(); ++c)
    1210            0 :                         for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh)
    1211              :                                 vvvLinDef[ip][c][sh] = 0.0;
    1212              : 
    1213              : //  loop Sub Control Volume Faces (SCVF)
    1214            0 :         for(size_t ip = 0; ip < geo.num_scvf(); ++ip)
    1215              :         {
    1216              :         // get current SCVF
    1217              :                 const typename TFVGeom::SCVF& scvf = geo.scvf(ip);
    1218              : 
    1219              :         //      sum up contributions of convection shapes
    1220              :                 MathVector<dim> linDefect;
    1221              :                 VecSet(linDefect, 0.0);
    1222            0 :                 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
    1223              :                         VecScaleAppend(linDefect, u(_C_,sh), convShape.D_vel(ip, sh));
    1224              : 
    1225              :         //      add parts for both sides of scvf
    1226            0 :                 vvvLinDef[ip][_C_][scvf.from()] += linDefect;
    1227              :                 vvvLinDef[ip][_C_][scvf.to()] -= linDefect;
    1228              :         }
    1229            0 : }
    1230              : 
    1231              : //      computes the linearized defect w.r.t to the velocity
    1232              : template<typename TDomain>
    1233              : template <typename TElem, typename TFVGeom>
    1234            0 : void ConvectionDiffusionFV1<TDomain>::
    1235              : lin_def_diffusion(const LocalVector& u,
    1236              :                   std::vector<std::vector<MathMatrix<dim,dim> > > vvvLinDef[],
    1237              :                   const size_t nip)
    1238              : {
    1239              : //  get finite volume geometry
    1240            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
    1241              : 
    1242              : //      get conv shapes
    1243            0 :         const IConvectionShapes<dim>& convShape = get_updated_conv_shapes(geo, true);
    1244              : 
    1245              : //      reset the values for the linearized defect
    1246            0 :         for(size_t ip = 0; ip < nip; ++ip)
    1247            0 :                 for(size_t c = 0; c < vvvLinDef[ip].size(); ++c)
    1248            0 :                         for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh)
    1249              :                                 vvvLinDef[ip][c][sh] = 0.0;
    1250              : 
    1251              : //  loop Sub Control Volume Faces (SCVF)
    1252            0 :         for(size_t ip = 0; ip < geo.num_scvf(); ++ip)
    1253              :         {
    1254              :         // get current SCVF
    1255              :                 const typename TFVGeom::SCVF& scvf = geo.scvf(ip);
    1256              : 
    1257              :         //      compute gradient at ip
    1258              :                 MathVector<dim> grad_u;   VecSet(grad_u, 0.0);
    1259            0 :                 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
    1260              :                         VecScaleAppend(grad_u, u(_C_,sh), scvf.global_grad(sh));
    1261              : 
    1262              :         //      compute the lin defect at this ip
    1263              :                 MathMatrix<dim,dim> linDefect;
    1264              : 
    1265              :         //      part coming from -\nabla u * \vec{n}
    1266            0 :                 for(size_t k=0; k < (size_t)dim; ++k)
    1267            0 :                         for(size_t j = 0; j < (size_t)dim; ++j)
    1268            0 :                                 linDefect(j,k) = (scvf.normal())[j] * grad_u[k];
    1269              : 
    1270              :         //      add contribution from convection shapes
    1271            0 :                 if(convShape.non_zero_deriv_diffusion())
    1272            0 :                         for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
    1273              :                                 MatAdd(linDefect, convShape.D_diffusion(ip, sh), u(_C_, sh));
    1274              : 
    1275              :         //      add contributions
    1276            0 :                 vvvLinDef[ip][_C_][scvf.from()] -= linDefect;
    1277              :                 vvvLinDef[ip][_C_][scvf.to()  ] += linDefect;
    1278              :         }
    1279            0 : }
    1280              : 
    1281              : template<typename TDomain>
    1282              : template <typename TElem, typename TFVGeom>
    1283            0 : void ConvectionDiffusionFV1<TDomain>::
    1284              : lin_def_flux(const LocalVector& u,
    1285              :              std::vector<std::vector<MathVector<dim> > > vvvLinDef[],
    1286              :              const size_t nip)
    1287              : {
    1288              : //  get finite volume geometry
    1289            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
    1290              : 
    1291              : //      reset the values for the linearized defect
    1292            0 :         for(size_t ip = 0; ip < nip; ++ip)
    1293            0 :                 for(size_t c = 0; c < vvvLinDef[ip].size(); ++c)
    1294            0 :                         for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh)
    1295              :                                 vvvLinDef[ip][c][sh] = 0.0;
    1296              : 
    1297              : //  loop Sub Control Volume Faces (SCVF)
    1298            0 :         for(size_t ip = 0; ip < geo.num_scvf(); ++ip)
    1299              :         {
    1300              :         // get current SCVF
    1301              :                 const typename TFVGeom::SCVF& scvf = geo.scvf(ip);
    1302              : 
    1303              :         //      add parts for both sides of scvf
    1304            0 :                 vvvLinDef[ip][_C_][scvf.from()] += scvf.normal();
    1305              :                 vvvLinDef[ip][_C_][scvf.to()] -= scvf.normal();
    1306              :         }
    1307            0 : }
    1308              : 
    1309              : //      computes the linearized defect w.r.t to the reaction rate
    1310              : template<typename TDomain>
    1311              : template <typename TElem, typename TFVGeom>
    1312            0 : void ConvectionDiffusionFV1<TDomain>::
    1313              : lin_def_reaction_rate(const LocalVector& u,
    1314              :                       std::vector<std::vector<number> > vvvLinDef[],
    1315              :                       const size_t nip)
    1316              : {
    1317              : //  get finite volume geometry
    1318            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
    1319              : 
    1320              : //      loop Sub Control Volumes (SCV)
    1321            0 :         for(size_t ip = 0; ip < geo.num_scv(); ++ip)
    1322              :         {
    1323              :         //      get current SCV
    1324              :                 const typename TFVGeom::SCV& scv = geo.scv(ip);
    1325              : 
    1326              :         //      get associated node
    1327            0 :                 const int co = scv.node_id();
    1328              : 
    1329              :         //      set lin defect
    1330            0 :                 vvvLinDef[ip][_C_][co] = u(_C_, co) * scv.volume();
    1331              :         }
    1332            0 : }
    1333              : 
    1334              : //      computes the linearized defect w.r.t to the reaction
    1335              : template<typename TDomain>
    1336              : template <typename TElem, typename TFVGeom>
    1337            0 : void ConvectionDiffusionFV1<TDomain>::
    1338              : lin_def_reaction(const LocalVector& u,
    1339              :                  std::vector<std::vector<number> > vvvLinDef[],
    1340              :                  const size_t nip)
    1341              : {
    1342              : //  get finite volume geometry
    1343            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
    1344              : 
    1345              : //      loop Sub Control Volumes (SCV)
    1346            0 :         for(size_t ip = 0; ip < geo.num_scv(); ++ip)
    1347              :         {
    1348              :         //      get current SCV
    1349              :                 const typename TFVGeom::SCV& scv = geo.scv(ip);
    1350              : 
    1351              :         //      get associated node
    1352            0 :                 const int co = scv.node_id();
    1353              : 
    1354              :         //      set lin defect
    1355            0 :                 vvvLinDef[ip][_C_][co] = scv.volume();
    1356              :         }
    1357            0 : }
    1358              : 
    1359              : //      computes the linearized defect w.r.t to the source
    1360              : template<typename TDomain>
    1361              : template <typename TElem, typename TFVGeom>
    1362            0 : void ConvectionDiffusionFV1<TDomain>::
    1363              : lin_def_source(const LocalVector& u,
    1364              :                std::vector<std::vector<number> > vvvLinDef[],
    1365              :                const size_t nip)
    1366              : {
    1367              : //  get finite volume geometry
    1368            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
    1369              : 
    1370              : //      loop Sub Control Volumes (SCV)
    1371            0 :         for(size_t ip = 0; ip < geo.num_scv(); ++ip)
    1372              :         {
    1373              :         //      get current SCV
    1374              :                 const typename TFVGeom::SCV& scv = geo.scv(ip);
    1375              : 
    1376              :         //      get associated node
    1377            0 :                 const int co = scv.node_id();
    1378              : 
    1379              :         //      set lin defect
    1380            0 :                 vvvLinDef[ip][_C_][co] = scv.volume();
    1381              :         }
    1382            0 : }
    1383              : 
    1384              : //      computes the linearized defect w.r.t to the vector source
    1385              : //      (in analogy to velocity)
    1386              : template<typename TDomain>
    1387              : template <typename TElem, typename TFVGeom>
    1388            0 : void ConvectionDiffusionFV1<TDomain>::
    1389              : lin_def_vector_source(const LocalVector& u,
    1390              :                       std::vector<std::vector<MathVector<dim> > > vvvLinDef[],
    1391              :                       const size_t nip)
    1392              : {
    1393              :         // get finite volume geometry
    1394            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
    1395              : 
    1396              : //      reset the values for the linearized defect
    1397            0 :         for(size_t ip = 0; ip < nip; ++ip)
    1398            0 :                 for(size_t c = 0; c < vvvLinDef[ip].size(); ++c)
    1399            0 :                         for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh)
    1400              :                                 vvvLinDef[ip][c][sh] = 0.0;
    1401              : 
    1402              :         // loop Sub Control Volumes Faces (SCVF)
    1403            0 :         for ( size_t ip = 0; ip < geo.num_scvf(); ++ip ) {
    1404              :                 // get current SCVF
    1405              :                 const typename TFVGeom::SCVF& scvf = geo.scvf( ip );
    1406              : 
    1407              :                 // add parts for both sides of scvf
    1408            0 :                 vvvLinDef[ip][_C_][scvf.from()] -= scvf.normal();
    1409              :                 vvvLinDef[ip][_C_][scvf.to()] += scvf.normal();
    1410              :         }
    1411            0 : }
    1412              : 
    1413              : //      computes the linearized defect w.r.t to the mass scale
    1414              : template<typename TDomain>
    1415              : template <typename TElem, typename TFVGeom>
    1416            0 : void ConvectionDiffusionFV1<TDomain>::
    1417              : lin_def_mass_scale(const LocalVector& u,
    1418              :                    std::vector<std::vector<number> > vvvLinDef[],
    1419              :                    const size_t nip)
    1420              : {
    1421              : //  get finite volume geometry
    1422            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
    1423              : 
    1424              : //      loop Sub Control Volumes (SCV)
    1425            0 :         for(size_t co = 0; co < geo.num_scv(); ++co)
    1426              :         {
    1427              :         //      get current SCV
    1428              :                 const typename TFVGeom::SCV& scv = geo.scv(co);
    1429              : 
    1430              :         //      Check associated node
    1431              :                 UG_ASSERT(co == scv.node_id(), "Only one shape per SCV");
    1432              : 
    1433              :         //      set lin defect
    1434            0 :                 vvvLinDef[co][_C_][co] = u(_C_, co) * scv.volume();
    1435              :         }
    1436            0 : }
    1437              : 
    1438              : //      computes the linearized defect w.r.t to the mass scale
    1439              : template<typename TDomain>
    1440              : template <typename TElem, typename TFVGeom>
    1441            0 : void ConvectionDiffusionFV1<TDomain>::
    1442              : lin_def_mass(const LocalVector& u,
    1443              :              std::vector<std::vector<number> > vvvLinDef[],
    1444              :              const size_t nip)
    1445              : {
    1446              : //  get finite volume geometry
    1447            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
    1448              : 
    1449              : //      loop Sub Control Volumes (SCV)
    1450            0 :         for(size_t co = 0; co < geo.num_scv(); ++co)
    1451              :         {
    1452              :         //      get current SCV
    1453              :                 const typename TFVGeom::SCV& scv = geo.scv(co);
    1454              : 
    1455              :         //      Check associated node
    1456              :                 UG_ASSERT(co == scv.node_id(), "Only one shape per SCV");
    1457              : 
    1458              :         //      set lin defect
    1459            0 :                 vvvLinDef[co][_C_][co] = scv.volume();
    1460              :         }
    1461            0 : }
    1462              : 
    1463              : //      computes the linearized defect w.r.t to the velocity
    1464              : template<typename TDomain>
    1465              : template <typename TElem, typename TFVGeom>
    1466            0 : void ConvectionDiffusionFV1<TDomain>::
    1467              : ex_value(number vValue[],
    1468              :          const MathVector<dim> vGlobIP[],
    1469              :          number time, int si,
    1470              :          const LocalVector& u,
    1471              :          GridObject* elem,
    1472              :          const MathVector<dim> vCornerCoords[],
    1473              :          const MathVector<TFVGeom::dim> vLocIP[],
    1474              :          const size_t nip,
    1475              :          bool bDeriv,
    1476              :          std::vector<std::vector<number> > vvvDeriv[])
    1477              : {
    1478              : //  get finite volume geometry
    1479            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
    1480              : 
    1481              : //      reference element
    1482              :         typedef typename reference_element_traits<TElem>::reference_element_type
    1483              :                         ref_elem_type;
    1484              : 
    1485              : //      number of shape functions
    1486              :         static const size_t numSH =     ref_elem_type::numCorners;
    1487              : 
    1488              : 
    1489              : //      FV1 SCVF ip
    1490            0 :         if(vLocIP == geo.scvf_local_ips())
    1491              :         {
    1492              :         //      Loop Sub Control Volume Faces (SCVF)
    1493            0 :                 for(size_t ip = 0; ip < geo.num_scvf(); ++ip)
    1494              :                 {
    1495              :                 //      Get current SCVF
    1496              :                         const typename TFVGeom::SCVF& scvf = geo.scvf(ip);
    1497              : 
    1498              :                 //      compute concentration at ip
    1499            0 :                         vValue[ip] = 0.0;
    1500            0 :                         for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
    1501            0 :                                 vValue[ip] += u(_C_, sh) * scvf.shape(sh);
    1502              : 
    1503              :                 //      compute derivative w.r.t. to unknowns iff needed
    1504            0 :                         if(bDeriv)
    1505              :                         {
    1506            0 :                                 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
    1507            0 :                                         vvvDeriv[ip][_C_][sh] = scvf.shape(sh);
    1508              : 
    1509              :                                 // do not forget that number of DoFs (== vvvDeriv[ip][_C_])
    1510              :                                 // might be > scvf.num_sh() in case of hanging nodes!
    1511            0 :                                 size_t ndof = vvvDeriv[ip][_C_].size();
    1512            0 :                                 for (size_t sh = scvf.num_sh(); sh < ndof; ++sh)
    1513            0 :                                         vvvDeriv[ip][_C_][sh] = 0.0;
    1514              :                         }
    1515              :                 }
    1516              :         }
    1517              : //      FV1 SCV ip
    1518            0 :         else if(vLocIP == geo.scv_local_ips())
    1519              :         {
    1520              :         //      Loop Sub Control Volumes (SCV)
    1521            0 :                 for(size_t ip = 0; ip < geo.num_scv(); ++ip)
    1522              :                 {
    1523              :                 //      Get current SCV
    1524              :                         const typename TFVGeom::SCV& scv = geo.scv(ip);
    1525              : 
    1526              :                 //      get corner of SCV
    1527              :                         const size_t co = scv.node_id();
    1528              : 
    1529              :                 //      solution at ip
    1530            0 :                         vValue[ip] = u(_C_, co);
    1531              : 
    1532              :                 //      set derivatives if needed
    1533            0 :                         if(bDeriv)
    1534              :                         {
    1535            0 :                                 size_t ndof = vvvDeriv[ip][_C_].size();
    1536            0 :                                 for(size_t sh = 0; sh < ndof; ++sh)
    1537            0 :                                         vvvDeriv[ip][_C_][sh] = (sh==co) ? 1.0 : 0.0;
    1538              :                         }
    1539              :                 }
    1540              :         }
    1541              : //      general case
    1542              :         else
    1543              :         {
    1544              :         //      get trial space
    1545            0 :                 LagrangeP1<ref_elem_type>& rTrialSpace = Provider<LagrangeP1<ref_elem_type> >::get();
    1546              : 
    1547              :         //      storage for shape function at ip
    1548              :                 number vShape[numSH];
    1549              : 
    1550              :         //      loop ips
    1551            0 :                 for(size_t ip = 0; ip < nip; ++ip)
    1552              :                 {
    1553              :                 //      evaluate at shapes at ip
    1554            0 :                         rTrialSpace.shapes(vShape, vLocIP[ip]);
    1555              : 
    1556              :                 //      compute concentration at ip
    1557            0 :                         vValue[ip] = 0.0;
    1558            0 :                         for(size_t sh = 0; sh < numSH; ++sh)
    1559            0 :                                 vValue[ip] += u(_C_, sh) * vShape[sh];
    1560              : 
    1561              :                 //      compute derivative w.r.t. to unknowns iff needed
    1562              :                 //      \todo: maybe store shapes directly in vvvDeriv
    1563            0 :                         if(bDeriv)
    1564              :                         {
    1565            0 :                                 for(size_t sh = 0; sh < numSH; ++sh)
    1566            0 :                                         vvvDeriv[ip][_C_][sh] = vShape[sh];
    1567              : 
    1568              :                                 // beware of hanging nodes!
    1569            0 :                                 size_t ndof = vvvDeriv[ip][_C_].size();
    1570            0 :                                 for (size_t sh = numSH; sh < ndof; ++sh)
    1571            0 :                                         vvvDeriv[ip][_C_][sh] = 0.0;
    1572              :                         }
    1573              :                 }
    1574              :         }
    1575            0 : }
    1576              : 
    1577              : //      computes the linearized defect w.r.t to the velocity
    1578              : template<typename TDomain>
    1579              : template <typename TElem, typename TFVGeom>
    1580            0 : void ConvectionDiffusionFV1<TDomain>::
    1581              : ex_grad(MathVector<dim> vValue[],
    1582              :         const MathVector<dim> vGlobIP[],
    1583              :         number time, int si,
    1584              :         const LocalVector& u,
    1585              :         GridObject* elem,
    1586              :         const MathVector<dim> vCornerCoords[],
    1587              :         const MathVector<TFVGeom::dim> vLocIP[],
    1588              :         const size_t nip,
    1589              :         bool bDeriv,
    1590              :         std::vector<std::vector<MathVector<dim> > > vvvDeriv[])
    1591              : {
    1592              : //      Get finite volume geometry
    1593            0 :         static const TFVGeom& geo = GeomProvider<TFVGeom>::get();
    1594              : 
    1595              : //      reference element
    1596              :         typedef typename reference_element_traits<TElem>::reference_element_type
    1597              :                         ref_elem_type;
    1598              : 
    1599              : //      reference dimension
    1600              :         static const int refDim = ref_elem_type::dim;
    1601              : 
    1602              : //      number of shape functions
    1603              :         static const size_t numSH =     ref_elem_type::numCorners;
    1604              : 
    1605              : 
    1606              : //      FV1 SCVF ip
    1607            0 :         if(vLocIP == geo.scvf_local_ips())
    1608              :         {
    1609              :         //      Loop Sub Control Volume Faces (SCVF)
    1610            0 :                 for(size_t ip = 0; ip < geo.num_scvf(); ++ip)
    1611              :                 {
    1612              :                 //      Get current SCVF
    1613              :                         const typename TFVGeom::SCVF& scvf = geo.scvf(ip);
    1614              : 
    1615            0 :                         VecSet(vValue[ip], 0.0);
    1616              : 
    1617            0 :                         for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
    1618              :                                 VecScaleAppend(vValue[ip], u(_C_, sh), scvf.global_grad(sh));
    1619              : 
    1620            0 :                         if(bDeriv)
    1621              :                         {
    1622            0 :                                 for(size_t sh = 0; sh < scvf.num_sh(); ++sh)
    1623            0 :                                         vvvDeriv[ip][_C_][sh] = scvf.global_grad(sh);
    1624              : 
    1625              :                                 // beware of hanging nodes!
    1626            0 :                                 size_t ndof = vvvDeriv[ip][_C_].size();
    1627            0 :                                 for (size_t sh = scvf.num_sh(); sh < ndof; ++sh)
    1628              :                                         vvvDeriv[ip][_C_][sh] = 0.0;
    1629              :                         }
    1630              :                 }
    1631              :         }
    1632              : //      general case
    1633              :         else
    1634              :         {
    1635              :         //      get trial space
    1636            0 :                 LagrangeP1<ref_elem_type>& rTrialSpace = Provider<LagrangeP1<ref_elem_type> >::get();
    1637              : 
    1638              :         //      storage for shape function at ip
    1639            0 :                 MathVector<refDim> vLocGrad[numSH];
    1640              :                 MathVector<refDim> locGrad;
    1641              : 
    1642              :         //      Reference Mapping
    1643              :                 MathMatrix<dim, refDim> JTInv;
    1644            0 :                 ReferenceMapping<ref_elem_type, dim> mapping(vCornerCoords);
    1645              : 
    1646              :         //      loop ips
    1647            0 :                 for(size_t ip = 0; ip < nip; ++ip)
    1648              :                 {
    1649              :                 //      evaluate at shapes at ip
    1650            0 :                         rTrialSpace.grads(vLocGrad, vLocIP[ip]);
    1651              : 
    1652              :                 //      compute grad at ip
    1653              :                         VecSet(locGrad, 0.0);
    1654            0 :                         for(size_t sh = 0; sh < numSH; ++sh)
    1655            0 :                                 VecScaleAppend(locGrad, u(_C_, sh), vLocGrad[sh]);
    1656              : 
    1657              :                 //      compute global grad
    1658            0 :                         mapping.jacobian_transposed_inverse(JTInv, vLocIP[ip]);
    1659            0 :                         MatVecMult(vValue[ip], JTInv, locGrad);
    1660              : 
    1661              :                 //      compute derivative w.r.t. to unknowns iff needed
    1662            0 :                         if(bDeriv)
    1663              :                         {
    1664            0 :                                 for(size_t sh = 0; sh < numSH; ++sh)
    1665            0 :                                         MatVecMult(vvvDeriv[ip][_C_][sh], JTInv, vLocGrad[sh]);
    1666              : 
    1667              :                                 // beware of hanging nodes!
    1668            0 :                                 size_t ndof = vvvDeriv[ip][_C_].size();
    1669            0 :                                 for (size_t sh = numSH; sh < ndof; ++sh)
    1670              :                                         vvvDeriv[ip][_C_][sh] = 0.0;
    1671              :                         }
    1672              :                 }
    1673              :         }
    1674            0 : };
    1675              : 
    1676              : ////////////////////////////////////////////////////////////////////////////////
    1677              : //      upwind
    1678              : ////////////////////////////////////////////////////////////////////////////////
    1679              : 
    1680              : template<typename TDomain>
    1681            0 : void ConvectionDiffusionFV1<TDomain>::
    1682            0 : set_upwind(SmartPtr<IConvectionShapes<dim> > shapes) {m_spConvShape = shapes;}
    1683              : 
    1684              : //      computes the linearized defect w.r.t to the velocity
    1685              : template<typename TDomain>
    1686              : const typename ConvectionDiffusionFV1<TDomain>::conv_shape_type&
    1687            0 : ConvectionDiffusionFV1<TDomain>::
    1688              : get_updated_conv_shapes(const FVGeometryBase& geo, bool compute_deriv)
    1689              : {
    1690              : //      compute upwind shapes for transport equation
    1691              : //      \todo: we should move this computation into the preparation part of the
    1692              : //                      disc, to only compute the shapes once, reusing them several times.
    1693            0 :         if(m_imVelocity.data_given())
    1694              :         {
    1695              :         //      get diffusion at ips
    1696              :                 const MathMatrix<dim, dim>* vDiffusion = NULL;
    1697            0 :                 if(m_imDiffusion.data_given()) vDiffusion = m_imDiffusion.values();
    1698              : 
    1699              :         //      update convection shapes
    1700            0 :                 if(!m_spConvShape->update(&geo, m_imVelocity.values(), vDiffusion, compute_deriv))
    1701              :                 {
    1702              :                         UG_LOG("ERROR in 'ConvectionDiffusionFV1::get_updated_conv_shapes': "
    1703              :                                         "Cannot compute convection shapes.\n");
    1704              :                 }
    1705              :         }
    1706              : 
    1707              : //      return a const (!!) reference to the upwind
    1708            0 :         return *const_cast<const IConvectionShapes<dim>*>(m_spConvShape.get());
    1709              : }
    1710              : 
    1711              : 
    1712              : ////////////////////////////////////////////////////////////////////////////////
    1713              : //      register assemble functions
    1714              : ////////////////////////////////////////////////////////////////////////////////
    1715              : 
    1716              : /**
    1717              :  * Registers the assembling functions for all the element types
    1718              :  */
    1719              : template<typename TDomain>
    1720            0 : void ConvectionDiffusionFV1<TDomain>::
    1721              : register_all_funcs(bool bHang)
    1722              : {
    1723              : //      list of element types for assembling
    1724              :         typedef typename domain_traits<dim>::AllElemList AssembleElemList;
    1725              :         
    1726              : //      register the local assembling functions
    1727            0 :         boost::mpl::for_each<AssembleElemList> (RegisterLocalDiscr (this, bHang));
    1728            0 : }
    1729              : 
    1730              : /**
    1731              :  * Registers the assembling functions for an element type.
    1732              :  */
    1733              : template<typename TDomain>
    1734              : template<typename TElem>
    1735              : void
    1736            0 : ConvectionDiffusionFV1<TDomain>::
    1737              : register_func_for_(bool bHang)
    1738              : {
    1739              : //      switch assemble functions
    1740            0 :         if(!bHang)
    1741              :         {
    1742            0 :                 if(!m_bCondensedFV)
    1743            0 :                         register_func<TElem, FV1Geometry<TElem, dim> >();
    1744              :                 else
    1745            0 :                         register_func<TElem, FV1CondensedGeometry<TElem, dim> >();
    1746              :         }
    1747              :         else
    1748              :         {
    1749            0 :                 if(m_bCondensedFV)
    1750            0 :                         UG_THROW("ConvectionDiffusionFV1: Condensed FV not supported for hanging nodes.");
    1751            0 :                 register_func<TElem, HFV1Geometry<TElem, dim> >();
    1752              :         }
    1753            0 : }
    1754              : 
    1755              : template<typename TDomain>
    1756              : template<typename TElem, typename TFVGeom>
    1757            0 : void ConvectionDiffusionFV1<TDomain>::
    1758              : register_func()
    1759              : {
    1760              :         ReferenceObjectID id = geometry_traits<TElem>::REFERENCE_OBJECT_ID;
    1761              :         typedef this_type T;
    1762              :         static const int refDim = reference_element_traits<TElem>::dim;
    1763              : 
    1764              :         this->clear_add_fct(id);
    1765              :         this->set_prep_elem_loop_fct(id, &T::template prep_elem_loop<TElem, TFVGeom>);
    1766              :         this->set_prep_elem_fct(      id, &T::template prep_elem<TElem, TFVGeom>);
    1767              :         this->set_fsh_elem_loop_fct( id, &T::template fsh_elem_loop<TElem, TFVGeom>);
    1768              :         this->set_add_jac_A_elem_fct(id, &T::template add_jac_A_elem<TElem, TFVGeom>);
    1769              :         this->set_add_jac_M_elem_fct(id, &T::template add_jac_M_elem<TElem, TFVGeom>);
    1770              :         this->set_add_def_A_elem_fct(id, &T::template add_def_A_elem<TElem, TFVGeom>);
    1771              :         this->set_add_def_A_expl_elem_fct(id, &T::template add_def_A_expl_elem<TElem, TFVGeom>);
    1772              :         this->set_add_def_M_elem_fct(id, &T::template add_def_M_elem<TElem, TFVGeom>);
    1773              :         this->set_add_rhs_elem_fct(  id, &T::template add_rhs_elem<TElem, TFVGeom>);
    1774              : 
    1775              : // error estimator parts
    1776              :         this->set_prep_err_est_elem_loop(id, &T::template prep_err_est_elem_loop<TElem, TFVGeom>);
    1777              :         this->set_prep_err_est_elem(id, &T::template prep_err_est_elem<TElem, TFVGeom>);
    1778              :         this->set_compute_err_est_A_elem(id, &T::template compute_err_est_A_elem<TElem, TFVGeom>);
    1779              :         this->set_compute_err_est_M_elem(id, &T::template compute_err_est_M_elem<TElem, TFVGeom>);
    1780              :         this->set_compute_err_est_rhs_elem(id, &T::template compute_err_est_rhs_elem<TElem, TFVGeom>);
    1781              :         this->set_fsh_err_est_elem_loop(id, &T::template fsh_err_est_elem_loop<TElem, TFVGeom>);
    1782              : 
    1783              : //      set computation of linearized defect w.r.t velocity
    1784            0 :         m_imDiffusion.set_fct(id, this, &T::template lin_def_diffusion<TElem, TFVGeom>);
    1785            0 :         m_imVelocity. set_fct(id, this, &T::template lin_def_velocity<TElem, TFVGeom>);
    1786            0 :         m_imFlux.set_fct(id, this, &T::template lin_def_flux<TElem, TFVGeom>);
    1787            0 :         m_imReactionRate. set_fct(id, this, &T::template lin_def_reaction_rate<TElem, TFVGeom>);
    1788            0 :         m_imReaction. set_fct(id, this, &T::template lin_def_reaction<TElem, TFVGeom>);
    1789            0 :         m_imSource.       set_fct(id, this, &T::template lin_def_source<TElem, TFVGeom>);
    1790            0 :         m_imVectorSource.set_fct(id, this, &T::template lin_def_vector_source<TElem, TFVGeom>);
    1791            0 :         m_imMassScale.set_fct(id, this, &T::template lin_def_mass_scale<TElem, TFVGeom>);
    1792            0 :         m_imMass.       set_fct(id, this, &T::template lin_def_mass<TElem, TFVGeom>);
    1793              : 
    1794              : //      exports
    1795            0 :         m_exValue->     template set_fct<T,refDim>(id, this, &T::template ex_value<TElem, TFVGeom>);
    1796            0 :         m_exGrad->template set_fct<T,refDim>(id, this, &T::template ex_grad<TElem, TFVGeom>);
    1797            0 : }
    1798              : 
    1799              : ////////////////////////////////////////////////////////////////////////////////
    1800              : //      explicit template instantiations
    1801              : ////////////////////////////////////////////////////////////////////////////////
    1802              : 
    1803              : #ifdef UG_DIM_1
    1804              : template class ConvectionDiffusionFV1<Domain1d>;
    1805              : #endif
    1806              : #ifdef UG_DIM_2
    1807              : template class ConvectionDiffusionFV1<Domain2d>;
    1808              : #endif
    1809              : #ifdef UG_DIM_3
    1810              : template class ConvectionDiffusionFV1<Domain3d>;
    1811              : #endif
    1812              : 
    1813              : } // end namespace ConvectionDiffusionPlugin
    1814              : } // namespace ug
    1815              : 
        

Generated by: LCOV version 2.0-1