void FV1InnerBoundaryElemDisc<TDomain>:: add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[]) { // get finite volume geometry const static TFVGeom& fvgeom = GeomProvider<TFVGeom>::get(); for (size_t i = 0; i < fvgeom.num_bf(); ++i) { // get current BF const typename TFVGeom::BF& bf = fvgeom.bf(i); // get associated node and subset index const int co = bf.node_id(); int si = fvgeom.subset_index(); // get solution at the corner of the bf size_t nFct = u.num_fct(); std::vector<LocalVector::value_type> uAtCorner(nFct); for (size_t fct = 0; fct < nFct; fct++) uAtCorner[fct] = u(fct,co); // get corner coordinates const MathVector<dim>& cc = bf.global_corner(0); FluxDerivCond fdc; if (!fluxDensityDerivFct(uAtCorner, elem, cc, si, fdc)) UG_THROW("FV1InnerBoundaryElemDisc::add_jac_A_elem:" " Call to fluxDensityDerivFct resulted did not succeed."); // scale with volume of BF for (size_t j=0; j<fdc.fluxDeriv.size(); j++) for (size_t k=0; k<fdc.fluxDeriv[j].size(); k++) fdc.fluxDeriv[j][k].second *= bf.volume(); // add to Jacobian for (size_t j=0; j<fdc.fluxDeriv.size(); j++) { for (size_t k=0; k<fdc.fluxDeriv[j].size(); k++) { if (fdc.from[j] != InnerBoundaryConstants::_IGNORE_) J(fdc.from[j], co, fdc.fluxDeriv[j][k].first, co) += fdc.fluxDeriv[j][k].second; if (fdc.to[j] != InnerBoundaryConstants::_IGNORE_) J(fdc.to[j], co, fdc.fluxDeriv[j][k].first, co) -= fdc.fluxDeriv[j][k].second; } } } }
void FV1InnerBoundaryElemDisc<TDomain>:: add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[]) { // get finite volume geometry static TFVGeom& fvgeom = GeomProvider<TFVGeom>::get(); // loop Boundary Faces for (size_t i = 0; i < fvgeom.num_bf(); ++i) { // get current BF const typename TFVGeom::BF& bf = fvgeom.bf(i); // get associated node and subset index const int co = bf.node_id(); int si = fvgeom.subset_index(); // get solution at the corner of the bf size_t nFct = u.num_fct(); std::vector<LocalVector::value_type> uAtCorner(nFct); for (size_t fct = 0; fct < nFct; fct++) uAtCorner[fct] = u(fct,co); // get corner coordinates const MathVector<dim>& cc = bf.global_corner(0); // get flux densities in that node FluxCond fc; if (!fluxDensityFct(uAtCorner, elem, cc, si, fc)) { UG_THROW("FV1InnerBoundaryElemDisc::add_def_A_elem:" " Call to fluxDensityFct did not succeed."); } // scale with volume of BF for (size_t j=0; j<fc.flux.size(); j++) fc.flux[j] *= bf.volume(); // add to defect for (size_t j=0; j<fc.flux.size(); j++) { if (fc.from[j] != InnerBoundaryConstants::_IGNORE_) d(fc.from[j], co) += fc.flux[j]; if (fc.to[j] != InnerBoundaryConstants::_IGNORE_) d(fc.to[j], co) -= fc.flux[j]; } } }
void FV1InnerBoundaryElemDisc<TDomain>:: compute_err_est_A_elem(const LocalVector& u, GridObject* elem, const MathVector<dim> vCornerCoords[], const number& scale) { // get error estimator err_est_type* err_est_data = dynamic_cast<err_est_type*>(this->m_spErrEstData.get()); // cast this elem to side_type of error estimator typename SideAndElemErrEstData<TDomain>::side_type* side = dynamic_cast<typename SideAndElemErrEstData<TDomain>::side_type*>(elem); if (!side) { UG_THROW("Error in DependentNeumannBoundaryFV1<TDomain>::compute_err_est_A_elem():\n" "Element that error assembling routine is called for has the wrong type."); } // global IPs ReferenceObjectID roid = side->reference_object_id(); size_t numSideIPs = err_est_data->get(0)->num_side_ips(roid); MathVector<dim>* globIPs = err_est_data->get(0)->side_global_ips(side, vCornerCoords); // loop IPs try { for (size_t sip = 0; sip < numSideIPs; sip++) { // get values of u at ip (interpolate) size_t nFct = u.num_fct(); std::vector<LocalVector::value_type> uAtIP = std::vector<LocalVector::value_type>(nFct); for (size_t fct = 0; fct < nFct; fct++) { uAtIP[fct] = 0.0; for (size_t sh = 0; sh < m_shapeValues.num_sh(); sh++) uAtIP[fct] += u(fct,sh) * m_shapeValues.shapeAtSideIP(sh,sip); } // ip coordinates const MathVector<dim>& ipCoords = globIPs[sip]; // elem subset int si = this->subset_handler().get_subset_index(side); FluxCond fc; if (!fluxDensityFct(uAtIP, elem, ipCoords, si, fc)) { UG_THROW("FV1InnerBoundaryElemDisc::compute_err_est_A_elem:" " Call to fluxDensityFct did not succeed."); } // subtract from estimator values // sign must be opposite of that in add_def_A_elem // as the difference between this and the actual flux of the unknown is calculated for (size_t j=0; j<fc.flux.size(); j++) { if (fc.from[j] != InnerBoundaryConstants::_IGNORE_) (*err_est_data->get(this->m_fctGrp[fc.from[j]])) (side,sip) -= scale * fc.flux[j]; if (fc.to[j] != InnerBoundaryConstants::_IGNORE_) (*err_est_data->get(this->m_fctGrp[fc.to[j]])) (side,sip) += scale * fc.flux[j]; } } } 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: MultipleSideAndElemErrEstData."); }