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

Generated by: LCOV version 2.0-1