// Actual evaluation of surface linear form (calculates integral) scalar FeProblem::eval_form(WeakForm::VectorFormSurf *vfs, Tuple<Solution *> u_ext, PrecalcShapeset *fv, RefMap *rv, EdgePos* ep) { // eval the form Quad2D* quad = fv->get_quad_2d(); int eo = quad->get_edge_points(ep->edge); double3* pt = quad->get_points(eo); int np = quad->get_num_points(eo); // init geometry and jacobian*weights if (cache_e[eo] == NULL) { cache_e[eo] = init_geom_surf(rv, ep, eo); double3* tan = rv->get_tangent(ep->edge); cache_jwt[eo] = new double[np]; for(int i = 0; i < np; i++) cache_jwt[eo][i] = pt[i][2] * tan[i][2]; } Geom<double>* e = cache_e[eo]; double* jwt = cache_jwt[eo]; // function values and values of external functions AUTOLA_OR(Func<scalar>*, prev, wf->neq); for (int i = 0; i < wf->neq; i++) prev[i] = init_fn(u_ext[i], rv, eo); Func<double>* v = get_fn(fv, rv, eo); ExtData<scalar>* ext = init_ext_fns(vfs->ext, rv, eo); scalar res = vfs->fn(np, jwt, prev, v, e, ext); for (int i = 0; i < wf->neq; i++) { prev[i]->free_fn(); delete prev[i]; } ext->free(); delete ext; return 0.5 * res; }
// checks whether the body can source its heads bool DefaultUnfoundedCheck::isValidSource(const BodyNodeP& n) { if (!n.node->extended()) { return bodies_[n.id].lower_or_ext == 0; } ExtData* ext = extended_[bodies_[n.id].lower_or_ext]; if (ext->lower > 0) { // Since n is currently not a source, // we here know that no literal with a source can depend on this body. // Hence, we can safely add all those literals to WS. // We check all internal literals here because there may be atoms // that were sourced *after* we established the watch set. const uint32 inc = n.node->pred_inc(); const NodeId* x = n.node->preds(); uint32 p = 0; for (; *x != idMax; x += inc, ++p) { if (atoms_[*x].hasSource() && !ext->inWs(p) && !solver_->isFalse(graph_->getAtomNode(*x).lit)) { ext->addToWs(p, n.node->pred_weight(p, false)); } } // We check all external literals here because we do not update // the body on backtracking. Therefore some external literals that were false // may now be true/free. for (++x; *x != idMax; x += inc, ++p) { if (!solver_->isFalse(Literal::fromRep(*x)) && !ext->inWs(p)) { ext->addToWs(p, n.node->pred_weight(p, true)); } } } return ext->lower <= 0; }
double KellyTypeAdapt::eval_boundary_estimator(KellyTypeAdapt::ErrorEstimatorForm* err_est_form, RefMap *rm, SurfPos* surf_pos) { // determine the integration order int inc = (this->sln[err_est_form->i]->get_num_components() == 2) ? 1 : 0; Func<Ord>** oi = new Func<Ord>* [num]; for (int i = 0; i < num; i++) oi[i] = init_fn_ord(this->sln[i]->get_edge_fn_order(surf_pos->surf_num) + inc); // Order of additional external functions. ExtData<Ord>* fake_ext = dp.init_ext_fns_ord(err_est_form->ext, surf_pos->surf_num); double fake_wt = 1.0; Geom<Ord>* fake_e = init_geom_ord(); Ord o = err_est_form->ord(1, &fake_wt, oi, oi[err_est_form->i], fake_e, fake_ext); int order = rm->get_inv_ref_order(); order += o.get_order(); limit_order(order); // Clean up. for (int i = 0; i < this->num; i++) if (oi[i] != NULL) { oi[i]->free_ord(); delete oi[i]; } delete [] oi; delete fake_e; delete fake_ext; // eval the form Quad2D* quad = this->sln[err_est_form->i]->get_quad_2d(); int eo = quad->get_edge_points(surf_pos->surf_num, order); double3* pt = quad->get_points(eo); int np = quad->get_num_points(eo); // init geometry and jacobian*weights Geom<double>* e = init_geom_surf(rm, surf_pos, eo); double3* tan = rm->get_tangent(surf_pos->surf_num, eo); double* jwt = new double[np]; for(int i = 0; i < np; i++) jwt[i] = pt[i][2] * tan[i][2]; // function values Func<scalar>** ui = new Func<scalar>* [num]; for (int i = 0; i < num; i++) ui[i] = init_fn(this->sln[i], eo); ExtData<scalar>* ext = dp.init_ext_fns(err_est_form->ext, rm, eo); scalar res = boundary_scaling_const * err_est_form->value(np, jwt, ui, ui[err_est_form->i], e, ext); for (int i = 0; i < this->num; i++) if (ui[i] != NULL) { ui[i]->free_fn(); delete ui[i]; } delete [] ui; if (ext != NULL) { ext->free(); delete ext; } e->free(); delete e; delete [] jwt; return std::abs(0.5*res); // Edges are parameterized from 0 to 1 while integration weights // are defined in (-1, 1). Thus multiplying with 0.5 to correct // the weights. }
double KellyTypeAdapt::eval_volumetric_estimator(KellyTypeAdapt::ErrorEstimatorForm* err_est_form, RefMap *rm) { // determine the integration order int inc = (this->sln[err_est_form->i]->get_num_components() == 2) ? 1 : 0; Func<Ord>** oi = new Func<Ord>* [num]; for (int i = 0; i < num; i++) oi[i] = init_fn_ord(this->sln[i]->get_fn_order() + inc); // Order of additional external functions. ExtData<Ord>* fake_ext = dp.init_ext_fns_ord(err_est_form->ext); double fake_wt = 1.0; Geom<Ord>* fake_e = init_geom_ord(); Ord o = err_est_form->ord(1, &fake_wt, oi, oi[err_est_form->i], fake_e, fake_ext); int order = rm->get_inv_ref_order(); order += o.get_order(); limit_order(order); // Clean up. for (int i = 0; i < this->num; i++) if (oi[i] != NULL) { oi[i]->free_ord(); delete oi[i]; } delete [] oi; delete fake_e; delete fake_ext; // eval the form Quad2D* quad = this->sln[err_est_form->i]->get_quad_2d(); double3* pt = quad->get_points(order); int np = quad->get_num_points(order); // init geometry and jacobian*weights Geom<double>* e = init_geom_vol(rm, order); double* jac = rm->get_jacobian(order); double* jwt = new double[np]; for(int i = 0; i < np; i++) jwt[i] = pt[i][2] * jac[i]; // function values Func<scalar>** ui = new Func<scalar>* [num]; for (int i = 0; i < num; i++) ui[i] = init_fn(this->sln[i], order); ExtData<scalar>* ext = dp.init_ext_fns(err_est_form->ext, rm, order); scalar res = volumetric_scaling_const * err_est_form->value(np, jwt, ui, ui[err_est_form->i], e, ext); for (int i = 0; i < this->num; i++) if (ui[i] != NULL) { ui[i]->free_fn(); delete ui[i]; } delete [] ui; if (ext != NULL) { ext->free(); delete ext; } e->free(); delete e; delete [] jwt; return std::abs(res); }
// an atom in extended body n has lost its source, check if n is no longer a valid source void DefaultUnfoundedCheck::RemoveSource::operator()(const BodyNodeP& n, NodeId atomId, uint32 idx) const { assert(n.node->extended() && n.node->get_pred(idx) == atomId); (void)atomId; ExtData* ext = self->extended_[self->bodies_[n.id].lower_or_ext]; ext->removeFromWs(idx, n.node->pred_weight(idx, false)); if (ext->lower > 0 && self->bodies_[n.id].watches > 0) { // extended bodies don't always become false if a predecessor becomes false // eagerly enqueue all successors watching this body self->forwardUnsource(n, true); } }
// Actual evaluation of volume matrix form (calculates integral) scalar FeProblem::eval_form(WeakForm::MatrixFormVol *mfv, Tuple<Solution *> u_ext, PrecalcShapeset *fu, PrecalcShapeset *fv, RefMap *ru, RefMap *rv) { // determine the integration order int inc = (fu->get_num_components() == 2) ? 1 : 0; AUTOLA_OR(Func<Ord>*, oi, wf->neq); for (int i = 0; i < wf->neq; i++) oi[i] = init_fn_ord(u_ext[i]->get_fn_order() + inc); Func<Ord>* ou = init_fn_ord(fu->get_fn_order() + inc); Func<Ord>* ov = init_fn_ord(fv->get_fn_order() + inc); ExtData<Ord>* fake_ext = init_ext_fns_ord(mfv->ext); double fake_wt = 1.0; Geom<Ord>* fake_e = init_geom_ord(); Ord o = mfv->ord(1, &fake_wt, oi, ou, ov, fake_e, fake_ext); int order = ru->get_inv_ref_order(); order += o.get_order(); limit_order_nowarn(order); for (int i = 0; i < wf->neq; i++) { oi[i]->free_ord(); delete oi[i]; } ou->free_ord(); delete ou; ov->free_ord(); delete ov; delete fake_e; fake_ext->free_ord(); delete fake_ext; // eval the form Quad2D* quad = fu->get_quad_2d(); double3* pt = quad->get_points(order); int np = quad->get_num_points(order); // init geometry and jacobian*weights if (cache_e[order] == NULL) { cache_e[order] = init_geom_vol(ru, order); double* jac = ru->get_jacobian(order); cache_jwt[order] = new double[np]; for(int i = 0; i < np; i++) cache_jwt[order][i] = pt[i][2] * jac[i]; } Geom<double>* e = cache_e[order]; double* jwt = cache_jwt[order]; // function values and values of external functions AUTOLA_OR(Func<scalar>*, prev, wf->neq); for (int i = 0; i < wf->neq; i++) prev[i] = init_fn(u_ext[i], rv, order); Func<double>* u = get_fn(fu, ru, order); Func<double>* v = get_fn(fv, rv, order); ExtData<scalar>* ext = init_ext_fns(mfv->ext, rv, order); scalar res = mfv->fn(np, jwt, prev, u, v, e, ext); for (int i = 0; i < wf->neq; i++) { prev[i]->free_fn(); delete prev[i]; } ext->free(); delete ext; return res; }
// an atom in extended body n has a new source, check if n is now a valid source void DefaultUnfoundedCheck::AddSource::operator()(const BodyNodeP& n, NodeId atomId, uint32 idx) const { assert(n.node->extended() && n.node->get_pred(idx) == atomId); (void)atomId; ExtData* ext = self->extended_[self->bodies_[n.id].lower_or_ext]; if (ext->lower > 0 || self->bodies_[n.id].watches == 0) { // currently not a source - safely add pred to our watch set ext->addToWs(idx, n.node->pred_weight(idx, false)); } if (!self->solver_->isFalse(n.node->lit) && ext->lower <= 0) { // valid source - propagate to heads self->forwardSource(n); } }
// check if n is part of the reason for the current unfounded set void DefaultUnfoundedCheck::addIfReason(const BodyNodeP& n, uint32 uScc) { if (solver_->isFalse(n.node->lit)) { if (n.node->scc != uScc) { addReasonLit(n.node->lit); } else if (!solver_->seen(n.node->lit)) { if (!n.node->extended()) { // body is only a reason if it does not depend on the atoms from the unfounded set for (const NodeId* x = n.node->preds(); *x != idMax; ++x) { if (atoms_[*x].ufs && !solver_->isFalse(graph_->getAtomNode(*x).lit)) { return; } } addReasonLit(n.node->lit); } else if (bodies_[n.id].picked == 0) { bodies_[n.id].picked = 1; reasonExt_.push_back(n.id); // Check if the body depends on the atoms from the unfounded set. I.e. // would the body still be false if all but its unfounded literals would be true? ExtData* ext = extended_[bodies_[n.id].lower_or_ext]; weight_t temp = ext->lower; const NodeId* x = n.node->preds(); const uint32 inc = n.node->pred_inc(); uint32 p = 0; for (; *x != idMax; x += inc, ++p) { if (!ext->inWs(p) && (atoms_[*x].ufs == 0 || solver_->isFalse(graph_->getAtomNode(*x).lit))) { if ( (temp -= n.node->pred_weight(p, false)) <= 0 ) { addReasonLit(n.node->lit); return; } } } for (++x; *x != idMax; x += inc, ++p) { if (!ext->inWs(p) && (temp -= n.node->pred_weight(p, true)) <= 0) { addReasonLit(n.node->lit); return; } } } } } else if (n.node->scc == uScc && n.node->extended() && bodies_[n.id].picked == 0) { bodies_[n.id].picked = 1; reasonExt_.push_back(n.id); // body is neither false nor a valid source - add all false lits to reason set AddReasonLit addFalseLits = { this }; graph_->visitBodyLiterals(n, addFalseLits); } }
///////////////////////////////////////////////////////////////////////////////////////// // DefaultUnfoundedCheck - Finding & propagating unfounded sets ///////////////////////////////////////////////////////////////////////////////////////// bool DefaultUnfoundedCheck::findUnfoundedSet() { // first: remove all sources that were recently falsified VarVec::size_type unpick = invalid_.size(); for (VarVec::size_type i = 0; i != invalidExt_.size(); ++i) { uint32 id = invalidExt_[i] >> 1; ExtWatch::Type t = static_cast<ExtWatch::Type>(invalidExt_[i] & 1u); if (t == ExtWatch::watch_choice_false) { if (atoms_[id].hasSource() && !solver_->isFalse(graph_->getBodyNode(atoms_[id].watch()).lit)) { atoms_[id].markSourceInvalid(); sourceQ_.push_back(id); propagateSource(true); } } else if (t == ExtWatch::watch_body_goal_false) { typedef DependencyGraph::BodyNode BodyNode; const ExtWatch& w = watches_[id]; BodyData& b = bodies_[w.bodyId]; ExtData* ext = extended_[b.lower_or_ext]; const BodyNode& B = graph_->getBodyNode(w.bodyId); NodeId pred = w.data >> 1; ext->removeFromWs(pred, B.pred_weight(pred, test_bit(w.data, 0) != 0)); if (ext->lower > 0 && b.watches && b.picked == 0 && !solver_->isFalse(B.lit)) { invalid_.push_back(w.bodyId); b.picked = 1; } } } for (VarVec::size_type i = 0; i != invalid_.size(); ++i) { removeSource(invalid_[i]); } for (VarVec::size_type i = unpick; i != invalid_.size(); ++i) { bodies_[invalid_[i]].picked = 0; } invalid_.clear(); invalidExt_.clear(); assert(sourceQ_.empty() && unfounded_.empty()); // second: try to re-establish sources. while (!todo_.empty()) { NodeId head = dequeueTodo(); if (!atoms_[head].hasSource() && !solver_->isFalse(graph_->getAtomNode(head).lit) && !findSource(head)) { return true; // found an unfounded set - contained in unfounded_ } assert(sourceQ_.empty()); } todo_.clear(); return false; // no unfounded sets }
double KellyTypeAdapt::eval_interface_estimator(KellyTypeAdapt::ErrorEstimatorForm* err_est_form, RefMap *rm, SurfPos* surf_pos, LightArray<NeighborSearch*>& neighbor_searches, int neighbor_index) { NeighborSearch* nbs = neighbor_searches.get(neighbor_index); Hermes::vector<MeshFunction*> slns; for (int i = 0; i < num; i++) slns.push_back(this->sln[i]); // Determine integration order. ExtData<Ord>* fake_ui = dp.init_ext_fns_ord(slns, neighbor_searches); // Order of additional external functions. // ExtData<Ord>* fake_ext = dp.init_ext_fns_ord(err_est_form->ext, nbs); // Order of geometric attributes (eg. for multiplication of a solution with coordinates, normals, etc.). Geom<Ord>* fake_e = new InterfaceGeom<Ord>(init_geom_ord(), nbs->neighb_el->marker, nbs->neighb_el->id, nbs->neighb_el->get_diameter()); double fake_wt = 1.0; Ord o = err_est_form->ord(1, &fake_wt, fake_ui->fn, fake_ui->fn[err_est_form->i], fake_e, NULL); int order = rm->get_inv_ref_order(); order += o.get_order(); limit_order(order); // Clean up. if (fake_ui != NULL) { for (int i = 0; i < num; i++) delete fake_ui->fn[i]; fake_ui->free_ord(); delete fake_ui; } delete fake_e; //delete fake_ext; Quad2D* quad = this->sln[err_est_form->i]->get_quad_2d(); int eo = quad->get_edge_points(surf_pos->surf_num, order); int np = quad->get_num_points(eo); double3* pt = quad->get_points(eo); // Init geometry and jacobian*weights (do not use the NeighborSearch caching mechanism). double3* tan = rm->get_tangent(surf_pos->surf_num, eo); double* jwt = new double[np]; for(int i = 0; i < np; i++) jwt[i] = pt[i][2] * tan[i][2]; Geom<double>* e = new InterfaceGeom<double>(init_geom_surf(rm, surf_pos, eo), nbs->neighb_el->marker, nbs->neighb_el->id, nbs->neighb_el->get_diameter()); // function values ExtData<scalar>* ui = dp.init_ext_fns(slns, neighbor_searches, order); //ExtData<scalar>* ext = dp.init_ext_fns(err_est_form->ext, nbs); scalar res = interface_scaling_const * err_est_form->value(np, jwt, ui->fn, ui->fn[err_est_form->i], e, NULL); if (ui != NULL) { ui->free(); delete ui; } //if (ext != NULL) { ext->free(); delete ext; } e->free(); delete e; delete [] jwt; return std::abs(0.5*res); // Edges are parameterized from 0 to 1 while integration weights // are defined in (-1, 1). Thus multiplying with 0.5 to correct // the weights. }