void ConvectionDiffusionFE<TDomain>:: add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[]) { // request geometry const TFEGeom& geo = GeomProvider<TFEGeom>::get(m_lfeID, m_quadOrder); number integrand, shape_u; MathMatrix<dim,dim> D; MathVector<dim> v, Dgrad_u, grad_u; // loop integration points for(size_t ip = 0; ip < geo.num_ip(); ++ip) { // get current u and grad_u VecSet(grad_u, 0.0); shape_u = 0.0; for(size_t j = 0; j < geo.num_sh(); ++j) { VecScaleAppend(grad_u, u(_C_,j), geo.global_grad(ip, j)); shape_u += u(_C_,j) * geo.shape(ip, j); } // Diffusion if(m_imDiffusion.data_given()) MatVecMult(Dgrad_u, m_imDiffusion[ip], grad_u); else VecSet(Dgrad_u, 0.0); // Convection if(m_imVelocity.data_given()) VecScaleAppend(Dgrad_u, -1*shape_u, m_imVelocity[ip]); // Convection if(m_imFlux.data_given()) VecScaleAppend(Dgrad_u, 1.0, m_imFlux[ip]); // loop test spaces for(size_t i = 0; i < geo.num_sh(); ++i) { // compute integrand integrand = VecDot(Dgrad_u, geo.global_grad(ip, i)); // add Reaction Rate if(m_imReactionRate.data_given()) integrand += m_imReactionRate[ip] * shape_u * geo.shape(ip, i); // add Reaction if(m_imReaction.data_given()) integrand += m_imReaction[ip] * geo.shape(ip, i); // multiply by integration weight integrand *= geo.weight(ip); // add to local defect d(_C_, i) += integrand; } } }
void ConvectionDiffusionFE<TDomain>:: lin_def_diffusion(const LocalVector& u, std::vector<std::vector<MathMatrix<dim,dim> > > vvvLinDef[], const size_t nip) { // request geometry const TFEGeom& geo = GeomProvider<TFEGeom>::get(m_lfeID, m_quadOrder); MathVector<dim> grad_u; // loop integration points for(size_t ip = 0; ip < geo.num_ip(); ++ip) { // get current u and grad_u VecSet(grad_u, 0.0); for(size_t j = 0; j < geo.num_sh(); ++j) VecScaleAppend(grad_u, u(_C_,j), geo.global_grad(ip, j)); // loop test spaces for(size_t i = 0; i < geo.num_sh(); ++i) { for(size_t k = 0; k < (size_t)dim; ++k) for(size_t j = 0; j < (size_t)dim; ++j) (vvvLinDef[ip][_C_][i])(k,j) = grad_u[j] * geo.global_grad(ip, i)[k] * geo.weight(ip); } } }
void ConvectionDiffusionFE<TDomain>:: add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[]) { // request geometry const TFEGeom& geo = GeomProvider<TFEGeom>::get(m_lfeID, m_quadOrder); MathVector<dim> v, Dgrad; // loop integration points for(size_t ip = 0; ip < geo.num_ip(); ++ip) { // loop trial space for(size_t j = 0; j < geo.num_sh(); ++j) { // Diffusion if(m_imDiffusion.data_given()) MatVecMult(Dgrad, m_imDiffusion[ip], geo.global_grad(ip, j)); else VecSet(Dgrad, 0.0); // Convection if(m_imVelocity.data_given()) VecScaleAppend(Dgrad, -1*geo.shape(ip,j), m_imVelocity[ip]); // no explicit dependency on m_imFlux // loop test space for(size_t i = 0; i < geo.num_sh(); ++i) { // compute integrand number integrand = VecDot(Dgrad, geo.global_grad(ip, i)); // Reaction if(m_imReactionRate.data_given()) integrand += m_imReactionRate[ip] * geo.shape(ip, j) * geo.shape(ip, i); // no explicit dependency on m_imReaction // multiply by weight integrand *= geo.weight(ip); // add to local matrix J(_C_, i, _C_, j) += integrand; } } } }
void ConvectionDiffusionFVCR<TDomain>:: lin_def_diffusion(const LocalVector& u, std::vector<std::vector<MathMatrix<dim,dim> > > vvvLinDef[], const size_t nip) { // get finite volume geometry static const TFVGeom& geo = GeomProvider<TFVGeom>::get(); // get conv shapes // const IConvectionShapes<dim>& convShape = get_updated_conv_shapes(geo); // reset the values for the linearized defect for(size_t ip = 0; ip < nip; ++ip) for(size_t c = 0; c < vvvLinDef[ip].size(); ++c) for(size_t sh = 0; sh < vvvLinDef[ip][c].size(); ++sh) vvvLinDef[ip][c][sh] = 0.0; // loop Sub Control Volume Faces (SCVF) for(size_t ip = 0; ip < geo.num_scvf(); ++ip) { // get current SCVF const typename TFVGeom::SCVF& scvf = geo.scvf(ip); // compute gradient at ip MathVector<dim> grad_u; VecSet(grad_u, 0.0); for(size_t sh = 0; sh < scvf.num_sh(); ++sh) VecScaleAppend(grad_u, u(_C_,sh), scvf.global_grad(sh)); // compute the lin defect at this ip MathMatrix<dim,dim> linDefect; // part coming from -\nabla u * \vec{n} for(size_t k=0; k < (size_t)dim; ++k) for(size_t j = 0; j < (size_t)dim; ++j) linDefect(j,k) = (scvf.normal())[j] * grad_u[k]; // add contribution from convection shapes // if(convShape.non_zero_deriv_diffusion()) // for(size_t sh = 0; sh < scvf.num_sh(); ++sh) // MatAdd(linDefect, convShape.D_diffusion(ip, sh), u(_C_, sh)); // add contributions vvvLinDef[ip][_C_][scvf.from()] -= linDefect; vvvLinDef[ip][_C_][scvf.to() ] += linDefect; } }
void ConvectionDiffusionFVCR<TDomain>:: ex_grad(MathVector<dim> vValue[], const MathVector<dim> vGlobIP[], number time, int si, const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[], const MathVector<TFVGeom::dim> vLocIP[], const size_t nip, bool bDeriv, std::vector<std::vector<MathVector<dim> > > vvvDeriv[]) { // Get finite volume geometry static const TFVGeom& geo = GeomProvider<TFVGeom>::get(); // reference element typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type; // reference dimension static const int refDim = ref_elem_type::dim; // number of shape functions static const size_t numSH = ref_elem_type::numCorners; // CRFV SCVF ip if(vLocIP == geo.scvf_local_ips()) { // Loop Sub Control Volume Faces (SCVF) for(size_t ip = 0; ip < geo.num_scvf(); ++ip) { // Get current SCVF const typename TFVGeom::SCVF& scvf = geo.scvf(ip); VecSet(vValue[ip], 0.0); for(size_t sh = 0; sh < scvf.num_sh(); ++sh) VecScaleAppend(vValue[ip], u(_C_, sh), scvf.global_grad(sh)); if(bDeriv) for(size_t sh = 0; sh < scvf.num_sh(); ++sh) vvvDeriv[ip][_C_][sh] = scvf.global_grad(sh); } } // general case else { // get trial space LagrangeP1<ref_elem_type>& rTrialSpace = Provider<LagrangeP1<ref_elem_type> >::get(); // storage for shape function at ip MathVector<refDim> vLocGrad[numSH]; MathVector<refDim> locGrad; // Reference Mapping MathMatrix<dim, refDim> JTInv; ReferenceMapping<ref_elem_type, dim> mapping(vCornerCoords); // loop ips for(size_t ip = 0; ip < nip; ++ip) { // evaluate at shapes at ip rTrialSpace.grads(vLocGrad, vLocIP[ip]); // compute grad at ip VecSet(locGrad, 0.0); for(size_t sh = 0; sh < numSH; ++sh) VecScaleAppend(locGrad, u(_C_, sh), vLocGrad[sh]); // compute global grad mapping.jacobian_transposed_inverse(JTInv, vLocIP[ip]); MatVecMult(vValue[ip], JTInv, locGrad); // compute derivative w.r.t. to unknowns iff needed if(bDeriv) for(size_t sh = 0; sh < numSH; ++sh) MatVecMult(vvvDeriv[ip][_C_][sh], JTInv, vLocGrad[sh]); } } };
void ConvectionDiffusionFVCR<TDomain>:: add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[]) { // get finite volume geometry static const TFVGeom& geo = GeomProvider<TFVGeom>::get(); // get conv shapes // const IConvectionShapes<dim>& convShape = get_updated_conv_shapes(geo); if(m_imDiffusion.data_given() || m_imVelocity.data_given()) { // loop Sub Control Volume Faces (SCVF) for(size_t ip = 0; ip < geo.num_scvf(); ++ip) { // get current SCVF const typename TFVGeom::SCVF& scvf = geo.scvf(ip); ///////////////////////////////////////////////////// // Diffusive Term ///////////////////////////////////////////////////// if(m_imDiffusion.data_given()) { // to compute D \nabla c MathVector<dim> Dgrad_c, grad_c; // compute gradient and shape at ip VecSet(grad_c, 0.0); for(size_t sh = 0; sh < scvf.num_sh(); ++sh) VecScaleAppend(grad_c, u(_C_,sh), scvf.global_grad(sh)); // scale by diffusion tensor MatVecMult(Dgrad_c, m_imDiffusion[ip], grad_c); // Compute flux const number diff_flux = VecDot(Dgrad_c, scvf.normal()); // Add to local defect d(_C_, scvf.from()) -= diff_flux; d(_C_, scvf.to() ) += diff_flux; } ///////////////////////////////////////////////////// // Convective Term ///////////////////////////////////////////////////// /* if(m_imVelocity.data_given()) { // sum up convective flux using convection shapes number conv_flux = 0.0; for(size_t sh = 0; sh < convShape.num_sh(); ++sh) conv_flux += u(_C_, sh) * convShape(ip, sh); // add to local defect d(_C_, scvf.from()) += conv_flux; d(_C_, scvf.to() ) -= conv_flux; }*/ } } // reaction rate if(m_imReactionRate.data_given()) { // loop Sub Control Volumes (SCV) for(size_t ip = 0; ip < geo.num_scv(); ++ip) { // get current SCV const typename TFVGeom::SCV& scv = geo.scv(ip); // get associated node const int co = scv.node_id(); // Add to local defect d(_C_, co) += u(_C_, co) * m_imReactionRate[ip] * scv.volume(); } } // reaction rate if(m_imReaction.data_given()) { // loop Sub Control Volumes (SCV) for(size_t ip = 0; ip < geo.num_scv(); ++ip) { // get current SCV const typename TFVGeom::SCV& scv = geo.scv(ip); // get associated node const int co = scv.node_id(); // Add to local defect d(_C_, co) += m_imReaction[ip] * scv.volume(); } } // handle constrained dofs, compute defect of interpolation equation if(TFVGeom::usesHangingNodes){ for (size_t i=0;i<geo.num_constrained_dofs();i++){ const typename TFVGeom::CONSTRAINED_DOF& cd = geo.constrained_dof(i); const size_t index = cd.index(); number defect = u(_C_,index); for (size_t j=0;j<cd.num_constraining_dofs();j++) defect -= cd.constraining_dofs_weight(j) * u(_C_,cd.constraining_dofs_index(j)); d(_C_,index) = defect; } } }
void ConvectionDiffusionFE<TDomain>:: compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[], const number& scale) { typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type; err_est_type* err_est_data = dynamic_cast<err_est_type*>(this->m_spErrEstData.get()); if (err_est_data->surface_view().get() == NULL) {UG_THROW("Error estimator has NULL surface view.");} MultiGrid* pErrEstGrid = (MultiGrid*) (err_est_data->surface_view()->subset_handler()->multi_grid()); // request geometry static const TFEGeom& geo = GeomProvider<TFEGeom>::get(); // SIDE TERMS // // get the sides of the element // We have to cast elem to a pointer of type SideAndElemErrEstData::elem_type // for the SideAndElemErrEstData::operator() to work properly. // This cannot generally be achieved by casting to TElem*, since this method is also registered for // lower-dimensional types TElem, and must therefore be compilable, even if it is never EVER to be executed. // The way we achieve this here, is by calling associated_elements_sorted() which has an implementation for // all possible types. Whatever comes out of it is of course complete nonsense if (and only if) // SideAndElemErrEstData::elem_type != TElem. To be on the safe side, we throw an error if the number of // entries in the list is not as it should be. typename MultiGrid::traits<typename SideAndElemErrEstData<TDomain>::side_type>::secure_container side_list; pErrEstGrid->associated_elements_sorted(side_list, (TElem*) elem); if (side_list.size() != (size_t) ref_elem_type::numSides) UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFE::compute_err_est_elem'"); // some help variables MathVector<dim> fluxDensity, gradC, normal; // FIXME: The computation of the gradient has to be reworked. // In the case of P1 shape functions, it is valid. For Q1 shape functions, however, // the gradient is not constant (but bilinear) on the element - and along the sides. // We cannot use the FVGeom here. Instead, we need to calculate the gradient in each IP! // calculate grad u as average (over scvf) VecSet(gradC, 0.0); for(size_t ii = 0; ii < geo.num_ip(); ++ii) { for (size_t j=0; j<m_shapeValues.num_sh(); j++) VecScaleAppend(gradC, u(_C_,j), geo.global_grad(ii, j)); } VecScale(gradC, gradC, (1.0/geo.num_ip())); // calculate flux through the sides size_t passedIPs = 0; for (size_t side=0; side < (size_t) ref_elem_type::numSides; side++) { // normal on side SideNormal<ref_elem_type,dim>(normal, side, vCornerCoords); VecNormalize(normal, normal); try { for (size_t sip = 0; sip < err_est_data->num_side_ips(side_list[side]); sip++) { size_t ip = passedIPs + sip; VecSet(fluxDensity, 0.0); // diffusion // if (m_imDiffusion.data_given()) MatVecScaleMultAppend(fluxDensity, -1.0, m_imDiffusion[ip], gradC); // convection // if (m_imVelocity.data_given()) { number val = 0.0; for (size_t sh = 0; sh < m_shapeValues.num_sh(); sh++) val += u(_C_,sh) * m_shapeValues.shapeAtSideIP(sh,sip); VecScaleAppend(fluxDensity, val, m_imVelocity[ip]); } // general flux // if (m_imFlux.data_given()) VecAppend(fluxDensity, m_imFlux[ip]); (*err_est_data)(side_list[side],sip) += scale * VecDot(fluxDensity, normal); } passedIPs += err_est_data->num_side_ips(side_list[side]); } UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); } // VOLUME TERMS // typename MultiGrid::traits<typename SideAndElemErrEstData<TDomain>::elem_type>::secure_container elem_list; pErrEstGrid->associated_elements_sorted(elem_list, (TElem*) elem); if (elem_list.size() != 1) UG_THROW ("Mismatch of numbers of sides in 'ConvectionDiffusionFE::compute_err_est_elem'"); try { for (size_t ip = 0; ip < err_est_data->num_elem_ips(elem->reference_object_id()); ip++) { number total = 0.0; // diffusion // TODO ONLY FOR (PIECEWISE) CONSTANT DIFFUSION TENSOR SO FAR! // div(D*grad(c)) // nothing to do, as c is piecewise linear and div(D*grad(c)) disappears // if D is diagonal and c bilinear, this should also vanish (confirm this!) // convection // TODO ONLY FOR (PIECEWISE) CONSTANT OR DIVERGENCE-FREE // VELOCITY FIELDS SO FAR! // div(v*c) = div(v)*c + v*grad(c) -- gradC has been calculated above if (m_imVelocity.data_given()) total += VecDot(m_imVelocity[ip], gradC); // general flux // TODO ONLY FOR DIVERGENCE-FREE FLUX FIELD SO FAR! // nothing to do // reaction // if (m_imReactionRate.data_given()) { number val = 0.0; for (size_t sh = 0; sh < geo.num_sh(); sh++) val += u(_C_,sh) * m_shapeValues.shapeAtElemIP(sh,ip); total += m_imReactionRate[ip] * val; } if (m_imReaction.data_given()) { total += m_imReaction[ip]; } (*err_est_data)(elem_list[0],ip) += scale * total; } } UG_CATCH_THROW("Values for the error estimator could not be assembled at every IP." << std::endl << "Maybe wrong type of ErrEstData object? This implementation needs: SideAndElemErrEstData."); }
void ConvectionDiffusionFE<TDomain>:: ex_grad(MathVector<dim> vValue[], const MathVector<dim> vGlobIP[], number time, int si, const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[], const MathVector<TFEGeom::dim> vLocIP[], const size_t nip, bool bDeriv, std::vector<std::vector<MathVector<dim> > > vvvDeriv[]) { // request geometry const TFEGeom& geo = GeomProvider<TFEGeom>::get(m_lfeID, m_quadOrder); // reference element typedef typename reference_element_traits<TElem>::reference_element_type ref_elem_type; // reference dimension static const int refDim = reference_element_traits<TElem>::dim; // reference object id static const ReferenceObjectID roid = ref_elem_type::REFERENCE_OBJECT_ID; // FE if(vLocIP == geo.local_ips()) { // Loop ip for(size_t ip = 0; ip < geo.num_ip(); ++ip) { VecSet(vValue[ip], 0.0); for(size_t sh = 0; sh < geo.num_sh(); ++sh) VecScaleAppend(vValue[ip], u(_C_, sh), geo.global_grad(ip, sh)); if(bDeriv) for(size_t sh = 0; sh < geo.num_sh(); ++sh) vvvDeriv[ip][_C_][sh] = geo.global_grad(ip, sh); } } // general case else { // request for trial space try{ const LocalShapeFunctionSet<refDim>& rTrialSpace = LocalFiniteElementProvider::get<refDim>(roid, m_lfeID); // number of shape functions const size_t numSH = rTrialSpace.num_sh(); // storage for shape function at ip std::vector<MathVector<refDim> > vLocGrad(numSH); MathVector<refDim> locGrad; // Reference Mapping MathMatrix<dim, refDim> JTInv; ReferenceMapping<ref_elem_type, dim> mapping(vCornerCoords); // loop ips for(size_t ip = 0; ip < nip; ++ip) { // evaluate at shapes at ip rTrialSpace.grads(vLocGrad, vLocIP[ip]); // compute grad at ip VecSet(locGrad, 0.0); for(size_t sh = 0; sh < numSH; ++sh) VecScaleAppend(locGrad, u(_C_, sh), vLocGrad[sh]); // compute global grad mapping.jacobian_transposed_inverse(JTInv, vLocIP[ip]); MatVecMult(vValue[ip], JTInv, locGrad); // compute derivative w.r.t. to unknowns iff needed if(bDeriv) for(size_t sh = 0; sh < numSH; ++sh) MatVecMult(vvvDeriv[ip][_C_][sh], JTInv, vLocGrad[sh]); } } UG_CATCH_THROW("ConvectionDiffusion::ex_grad: trial space missing."); } };
void GradientDataExport<dim>::eval_and_deriv(MathVector<dim> vValue[], const MathVector<dim> vGlobIP[], number time, int si, GridObject* elem, const MathVector<dim> vCornerCoords[], const MathVector<refDim> vLocIP[], const size_t nip, LocalVector* u, bool bDeriv, int s, std::vector<std::vector<MathVector<dim> > > vvvDeriv[], const MathMatrix<refDim, dim>* vJT) const { // abbreviation for component static const int _C_ = 0; // reference object id const ReferenceObjectID roid = elem->reference_object_id(); // local finite element id const LFEID& lfeID = this->function_group().local_finite_element_id(_C_); // access local vector by map u->access_by_map(this->map()); // request for trial space try{ const LocalShapeFunctionSet<refDim>& rTrialSpace = LocalFiniteElementProvider::get<refDim>(roid, lfeID); // Reference Mapping MathMatrix<dim, refDim> JTInv; std::vector<MathMatrix<refDim, dim> > vJTtmp; if(!vJT){ DimReferenceMapping<refDim, dim>& map = ReferenceMappingProvider::get<refDim, dim>(roid, vCornerCoords); vJTtmp.resize(nip); map.jacobian_transposed(&vJTtmp[0], vLocIP, nip); vJT = &vJTtmp[0]; } // storage for shape function at ip std::vector<MathVector<refDim> > vLocGrad; MathVector<refDim> locGrad; // loop ips for(size_t ip = 0; ip < nip; ++ip) { // evaluate at shapes at ip rTrialSpace.grads(vLocGrad, vLocIP[ip]); // compute grad at ip VecSet(locGrad, 0.0); for(size_t sh = 0; sh < vLocGrad.size(); ++sh) VecScaleAppend(locGrad, (*u)(_C_, sh), vLocGrad[sh]); Inverse(JTInv, vJT[ip]); MatVecMult(vValue[ip], JTInv, locGrad); // store derivative if(bDeriv) for(size_t sh = 0; sh < vLocGrad.size(); ++sh) MatVecMult(vvvDeriv[ip][_C_][sh], JTInv, vLocGrad[sh]); } } UG_CATCH_THROW("GradientDataExport: Trial space missing, Reference Object: " <<roid<<", Trial Space: "<<lfeID<<", refDim="<<refDim); }