void ReturnByRef::apply() { RefMap map; RefMap::iterator iter; FnSet asgnUpdates; returnByRefCollectCalls(map, asgnUpdates); for (iter = map.begin(); iter != map.end(); iter++) iter->second->transform(); for_set(FnSymbol, fn, asgnUpdates) updateAssignments(fn); for (int i = 0; i < virtualMethodTable.n; i++) { if (virtualMethodTable.v[i].key) { int numFns = virtualMethodTable.v[i].value->n; for (int j = 0; j < numFns; j++) { FnSymbol* fn = virtualMethodTable.v[i].value->v[j]; TransformationKind tfKind = transformableFunctionKind(fn); if (tfKind == TF_FULL) transformFunction(fn); else if (tfKind == TF_ASGN) updateAssignments(fn); } } } }
// Custom function to calculate drag coefficient. double integrate_over_wall(MeshFunction* meshfn, int marker) { Quad2D* quad = &g_quad_2d_std; meshfn->set_quad_2d(quad); double integral = 0.0; Element* e; Mesh* mesh = meshfn->get_mesh(); for_all_active_elements(e, mesh) { for(int edge = 0; edge < e->nvert; edge++) { if ((e->en[edge]->bnd) && (e->en[edge]->marker == marker)) { update_limit_table(e->get_mode()); RefMap* ru = meshfn->get_refmap(); meshfn->set_active_element(e); int eo = quad->get_edge_points(edge); meshfn->set_quad_order(eo, H2D_FN_VAL); scalar *uval = meshfn->get_fn_values(); double3* pt = quad->get_points(eo); double3* tan = ru->get_tangent(edge); for (int i = 0; i < quad->get_num_points(eo); i++) integral += pt[i][2] * uval[i] * tan[i][2]; } } } return integral * 0.5; }
void ReturnByRef::returnByRefCollectCalls(RefMap& calls) { RefMap::iterator iter; forv_Vec(CallExpr, call, gCallExprs) { if (FnSymbol* fn = theTransformableFunction(call)) { RefMap::iterator iter = calls.find(fn->id); ReturnByRef* info = NULL; if (iter == calls.end()) { info = new ReturnByRef(fn); calls[fn->id] = info; } else { info = iter->second; } info->addCall(call); } } }
// Calculates maximum of a given function, including its coordinates. Extremum get_peak(MeshFunction *sln) { Quad2D* quad = &g_quad_2d_std; sln->set_quad_2d(quad); Element* e; Mesh* mesh = sln->get_mesh(); scalar peak = 0.0; double pos_x = 0.0; double pos_y = 0.0; for_all_active_elements(e, mesh) { update_limit_table(e->get_mode()); sln->set_active_element(e); RefMap* ru = sln->get_refmap(); int o = sln->get_fn_order() + ru->get_inv_ref_order(); limit_order(o); sln->set_quad_order(o, H2D_FN_VAL); scalar *uval = sln->get_fn_values(); int np = quad->get_num_points(o); double* x = ru->get_phys_x(o); double* y = ru->get_phys_y(o); for (int i = 0; i < np; i++) if (uval[i] > peak) { peak = uval[i]; pos_x = x[i]; pos_y = y[i]; } }
//------------------------------------------------------------------------------ // Compute marked boundary length // double CalculateBoundaryLength(Mesh* mesh, int bdryMarker) { // Variables declaration. Element* e; double length = 0; RefMap rm; rm.set_quad_2d(&g_quad_2d_std); Quad2D * quad = rm.get_quad_2d(); int points_location; double3* points; int np; double3* tangents; // Loop through all boundary faces of all active elements. for_all_active_elements(e, mesh) { for(int edge = 0; edge < e->nvert; ++edge) { if ((e->en[edge]->bnd) && (e->en[edge]->marker == bdryMarker)) { rm.set_active_element(e); points_location = quad->get_edge_points(edge); points = quad->get_points(points_location); np = quad->get_num_points(points_location); tangents = rm.get_tangent(edge, points_location); for(int i = 0; i < np; i++) { // Weights sum up to two on every edge, therefore the division by two must be present. length += 0.5 * points[i][2] * tangents[i][2]; } } } } return length; } // end of CalculateBoundaryLength()
/// Calculates the absolute error between sln1 and sln2 using function fn double calc_error(double (*fn)(MeshFunction*, MeshFunction*, int, QuadPt3D*), MeshFunction *sln1, MeshFunction *sln2) { _F_ Mesh *meshes[2] = { sln1->get_mesh(), sln2->get_mesh() }; Transformable *tr[2] = { sln1, sln2 }; Traverse trav; trav.begin(2, meshes, tr); double error = 0.0; Element **ee; while ((ee = trav.get_next_state(NULL, NULL)) != NULL) { ElementMode3D mode = ee[0]->get_mode(); RefMap *ru = sln1->get_refmap(); Ord3 order = max(sln1->get_fn_order(), sln2->get_fn_order()) + ru->get_inv_ref_order(); order.limit(); Quad3D *quad = get_quadrature(mode); int np = quad->get_num_points(order); QuadPt3D *pt = quad->get_points(order); error += fn(sln1, sln2, np, pt); } trav.finish(); return error > H3D_TINY ? sqrt(error) : error; // do not ruin the precision by taking the sqrt }
// Integral over the active core. double integrate(MeshFunction* sln, int marker) { Quad2D* quad = &g_quad_2d_std; sln->set_quad_2d(quad); double integral = 0.0; Element* e; Mesh* mesh = sln->get_mesh(); for_all_active_elements(e, mesh) { if (e->marker == marker) { update_limit_table(e->get_mode()); sln->set_active_element(e); RefMap* ru = sln->get_refmap(); int o = sln->get_fn_order() + ru->get_inv_ref_order(); limit_order(o); sln->set_quad_order(o, H2D_FN_VAL); scalar *uval = sln->get_fn_values(); double* x = ru->get_phys_x(o); double result = 0.0; h1_integrate_expression(x[i] * uval[i]); integral += result; } } return 2.0 * M_PI * integral; }
void CacheGitDirectory::registerEntryInRefMap(const std::string& hash, RefMap& refMap) { assert(isInRef()); /* Find the cache entry that corresponds to this hash. * Create a new entry if not found. */ auto itFind = gitHashMap_.find(hash); GitCacheEntry* entry; if (itFind == gitHashMap_.end()) { entry = new GitCacheEntry(); entry->hash = hash; gitHashMap_[hash] = entry; } else { entry = itFind->second; } /* Look in the refMap for any CacheEntry that was already linked to the * current git ref. */ auto itPrevEntry = refMap.find(currentGitRef_); if (itPrevEntry != refMap.end()) { GitCacheEntry* prevEntry = itPrevEntry->second; assert(prevEntry->numGitRefs > 0); prevEntry->numGitRefs--; if (prevEntry->numGitRefs == 0 && prevEntry != entry) { DLOG(INFO) << "deleting " << prevEntry->hash; cacheFs_.delEntry(prevEntry->hash); gitHashMap_.erase(prevEntry->hash); delete prevEntry; } } refMap[currentGitRef_] = entry; entry->numGitRefs++; }
void loadNiTriShapeData(Niflib::NiTriShapeRef parent, Niflib::NiTriShapeDataRef data, RefMap& refmap) { Renderable *result; if (parent->GetSkinInstance()) { SkinnedMesh *mesh = new SkinnedMesh(true); loadNiTriShapeVertices(mesh, data); loadNiTriShapeMaterial(mesh, parent); loadNiSkinInstance(mesh, parent->GetSkinInstance(), refmap); mesh->parent = refmap.getNode(parent); result = mesh; } else { Mesh *mesh = new Mesh(true); loadNiTriShapeVertices(mesh, data); loadNiTriShapeMaterial(mesh, parent); mesh->parent = refmap.getNode(parent); result = mesh; } refmap.currentModel->addRenderable(result); }
// Integral over the active core. double integrate(MeshFunction<double>* sln, std::string area) { Quad2D* quad = &g_quad_2d_std; sln->set_quad_2d(quad); double integral = 0.0; Element* e; Mesh* mesh = const_cast<Mesh*>(sln->get_mesh()); int marker = mesh->get_element_markers_conversion().get_internal_marker(area).marker; for_all_active_elements(e, mesh) { if (e->marker == marker) { update_limit_table(e->get_mode()); sln->set_active_element(e); RefMap* ru = sln->get_refmap(); int o = sln->get_fn_order() + ru->get_inv_ref_order(); limit_order(o, e->get_mode()); sln->set_quad_order(o, H2D_FN_VAL); double *uval = sln->get_fn_values(); double* x = ru->get_phys_x(o); double result = 0.0; h1_integrate_expression(x[i] * uval[i]); integral += result; } } return 2.0 * M_PI * integral; }
void ReturnByRef::apply() { RefMap map; RefMap::iterator iter; returnByRefCollectCalls(map); for (iter = map.begin(); iter != map.end(); iter++) iter->second->transform(); for (int i = 0; i < virtualMethodTable.n; i++) { if (virtualMethodTable.v[i].key) { int numFns = virtualMethodTable.v[i].value->n; for (int j = 0; j < numFns; j++) { FnSymbol* fn = virtualMethodTable.v[i].value->v[j]; if (isTransformableFunction(fn)) transformFunction(fn); } } } }
// Insert pairs into available copies map // Also, record references when they are created. static void extractReferences(Expr* expr, RefMap& refs) { // We're only interested in call expressions. if (CallExpr* call = toCallExpr(expr)) { // Only the move primitive creates an available pair. if (call->isPrimitive(PRIM_MOVE) || call->isPrimitive(PRIM_ASSIGN)) { SymExpr* lhe = toSymExpr(call->get(1)); // Left-Hand Expression Symbol* lhs = lhe->var; // Left-Hand Symbol if (SymExpr* rhe = toSymExpr(call->get(2))) // Right-Hand Expression { Symbol* rhs = rhe->var; // Right-Hand Symbol if (lhs->type->symbol->hasFlag(FLAG_REF) && rhs->type->symbol->hasFlag(FLAG_REF)) { // This is a ref <- ref assignment. // Which means that the lhs is now also a reference to whatever the // rhs refers to. RefMap::iterator refDef = refs.find(rhs); // Refs can come from outside the function (e.g. through arguments), // so are not necessarily defined within the function. if (refDef != refs.end()) { Symbol* val = refDef->second; #if DEBUG_CP if (debug > 0) printf("Creating ref (%s[%d], %s[%d])\n", lhs->name, lhs->id, val->name, val->id); #endif refs.insert(RefMapElem(lhs, val)); } } } if (CallExpr* rhc = toCallExpr(call->get(2))) { if (rhc->isPrimitive(PRIM_ADDR_OF)) { SymExpr* rhe = toSymExpr(rhc->get(1)); // Create the pair lhs <- &rhs. Symbol* lhs = lhe->var; Symbol* rhs = rhe->var; #if DEBUG_CP if (debug > 0) printf("Creating ref (%s[%d], %s[%d])\n", lhs->name, lhs->id, rhs->name, rhs->id); #endif refs.insert(RefMapElem(lhs, rhs)); } } } } }
void loadNiKeyframeController(Niflib::NiKeyframeControllerRef obj, RefMap& refmap) { //make a new animation controller KeyframeAnimationObject *result = new KeyframeAnimationObject(); //load data result->length = obj->GetStopTime(); Niflib::NiKeyframeDataRef data = Niflib::DynamicCast<Niflib::NiKeyframeData>(obj->GetData()); for (Niflib::Key<Niflib::Vector3> key: data->GetTranslateKeys()) { result->positionKeys.addKey(key.time, NifToGlmVec3(key.data)); } for (Niflib::Key<Niflib::Quaternion> key: data->GetQuatRotateKeys()) { result->rotationKeys.addKey(key.time, NifToGlmQuat(key.data)); } for (Niflib::Key<float> key: data->GetScaleKeys()) { result->scaleKeys.addKey(key.time, glm::vec3(key.data, key.data, key.data)); } result->setTarget(refmap.getNode(obj->GetTarget())); refmap.currentModel->addController(result); }
void loadNiSkinInstance(SkinnedMesh *mesh, Niflib::NiSkinInstanceRef skin, RefMap& refmap) { Niflib::NiSkinDataRef skindata = skin->GetSkinData(); for (unsigned int ibone=0; ibone<skin->GetBoneCount(); ibone++) { mesh->bones.push_back(refmap.getNode(skin->GetBones()[ibone])); Niflib::Matrix44 offset = skindata->GetBoneTransform(ibone); mesh->boneOffsets.push_back(NifToGlmMat4(offset)); for (Niflib::SkinWeight weight: skindata->GetBoneWeights(ibone)) { mesh->vertices->get(weight.index).addBone(ibone, weight.weight); } } mesh->root = refmap.getNode(skin->GetSkeletonRoot()); }
/// Calculates the norm of sln using function fn double calc_norm(double (*fn)(MeshFunction*, int, QuadPt3D*), MeshFunction *sln) { _F_ double norm = 0.0; Mesh *mesh = sln->get_mesh(); FOR_ALL_ACTIVE_ELEMENTS(eid, mesh) { Element *e = mesh->elements[eid]; sln->set_active_element(e); RefMap *ru = sln->get_refmap(); order3_t o = sln->get_fn_order() + ru->get_inv_ref_order(); o.limit(); Quad3D *quad = get_quadrature(e->get_mode()); int np = quad->get_num_points(o); QuadPt3D *pt = quad->get_points(o); norm += fn(sln, np, pt); }
void ReturnByRef::returnByRefCollectCalls(RefMap& calls, FnSet& fns) { RefMap::iterator iter; forv_Vec(CallExpr, call, gCallExprs) { // Only transform calls that are still in the AST tree // (defer statement bodies have been removed at this point // in this pass) if (call->inTree()) { // Only transform calls to transformable functions // The common case is a user-level call to a resolved function // Also handle the PRIMOP for a virtual method call if (FnSymbol* fn = call->resolvedOrVirtualFunction()) { TransformationKind tfKind = transformableFunctionKind(fn); if (tfKind == TF_FULL) { RefMap::iterator iter = calls.find(fn->id); ReturnByRef* info = NULL; if (iter == calls.end()) { info = new ReturnByRef(fn); calls[fn->id] = info; } else { info = iter->second; } info->addCall(call); } else if (tfKind == TF_ASGN) { fns.insert(fn); } } } } }
void loadNiNode(Niflib::NiAVObjectRef node, RefMap& refmap) { //make a new node Node *result = refmap.getNode(node); //load data result->setName(node->GetName()); result->setPosition(NifToGlmVec3(node->GetLocalTranslation())); result->setRotation(NifToGlmQuat(node->GetLocalRotation().AsQuaternion())); result->setScale(glm::vec3(node->GetLocalScale(),node->GetLocalScale(),node->GetLocalScale())); for (Niflib::NiExtraDataRef& extradata: node->GetExtraData()) { if (extradata->GetType().IsSameType(Niflib::NiStringExtraData::TYPE)) { Niflib::NiStringExtraDataRef strdata = Niflib::DynamicCast<Niflib::NiStringExtraData>( extradata); if (strdata->GetData() == "NCO") { refmap.hasCollision = false; } } } if (node->GetType().IsSameType(Niflib::NiTriShape::TYPE)) { Niflib::NiTriShapeRef temp = Niflib::DynamicCast<Niflib::NiTriShape>(node); Niflib::NiTriShapeDataRef tempdata = Niflib::DynamicCast<Niflib::NiTriShapeData>(temp->GetData()); loadNiTriShapeData(temp, tempdata, refmap); } else if (node->GetType().IsSameType(Niflib::RootCollisionNode::TYPE)) { refmap.collisionnode = Niflib::DynamicCast<Niflib::RootCollisionNode>(node); } result->isVisible = node->GetVisibility(); //attach this node to its parent Niflib::NiNodeRef parent = node->GetParent(); if (parent) { Node *parnode = refmap.getNode(parent); parnode->addChild(result); } refmap.currentModel->addNamedNode(node->GetName(), result); }
void DiscreteProblem::precalc_equi_coefs() { int i, m; memset(equi, 0, sizeof(double) * ndofs); verbose("Precalculating equilibration coefficients..."); RefMap refmap; AsmList al; Element* e; for (m = 0; m < neq; m++) { PrecalcShapeset* fu = pss[m]; BiForm* bf = biform[m] + m; Mesh* mesh = spaces[m]->get_mesh(); for_all_active_elements(e, mesh) { update_limit_table(e->get_mode()); fu->set_active_element(e); refmap.set_active_element(e); spaces[m]->get_element_assembly_list(e, &al); for (i = 0; i < al.cnt; i++) { if (al.dof[i] < 0) continue; fu->set_active_shape(al.idx[i]); scalar sy = 0.0, un = 0.0; if (bf->unsym) un = bf->unsym(fu, fu, &refmap, &refmap); if (bf->sym) sy = bf->sym (fu, fu, &refmap, &refmap); #ifndef COMPLEX equi[al.dof[i]] += (sy + un) * sqr(al.coef[i]); #else equi[al.dof[i]] += 0;//std::norm(sy + un) * sqr(al.coef[i]); #endif } } }
/// Calculates the norm of sln using function fn double calc_norm(double (*fn)(MeshFunction*, int, QuadPt3D*), MeshFunction *sln) { _F_ double norm = 0.0; Mesh *mesh = sln->get_mesh(); for(std::map<unsigned int, Element*>::iterator it = mesh->elements.begin(); it != mesh->elements.end(); it++) if (it->second->used && it->second->active) { Element *e = mesh->elements[it->first]; sln->set_active_element(e); RefMap *ru = sln->get_refmap(); Ord3 o = sln->get_fn_order() + ru->get_inv_ref_order(); o.limit(); Quad3D *quad = get_quadrature(e->get_mode()); int np = quad->get_num_points(o); QuadPt3D *pt = quad->get_points(o); norm += fn(sln, np, pt); } return norm > H3D_TINY ? sqrt(norm) : norm; // do not ruin the precision by taking the sqrt }
/// Calculate number of negative solution values. int get_num_of_neg(MeshFunction *sln) { Quad2D* quad = &g_quad_2d_std; sln->set_quad_2d(quad); Element* e; Mesh* mesh = sln->get_mesh(); int n = 0; for_all_active_elements(e, mesh) { update_limit_table(e->get_mode()); sln->set_active_element(e); RefMap* ru = sln->get_refmap(); int o = sln->get_fn_order() + ru->get_inv_ref_order(); limit_order(o); sln->set_quad_order(o, H2D_FN_VAL); scalar *uval = sln->get_fn_values(); int np = quad->get_num_points(o); for (int i = 0; i < np; i++) if (uval[i] < -1e-12) n++; }
void Orderizer::process_space(SpaceSharedPtr<Scalar> space, bool show_edge_orders) { // sanity check if (space == nullptr) throw Hermes::Exceptions::Exception("Space is nullptr in Orderizer:process_space()."); if (!space->is_up_to_date()) throw Hermes::Exceptions::Exception("The space is not up to date."); MeshSharedPtr mesh = space->get_mesh(); // Reallocate. this->reallocate(mesh); RefMap refmap; int oo, o[6]; // make a mesh illustrating the distribution of polynomial orders over the space Element* e; for_all_active_elements(e, mesh) { oo = o[4] = o[5] = space->get_element_order(e->id); if (show_edge_orders) for (unsigned int k = 0; k < e->get_nvert(); k++) o[k] = space->get_edge_order(e, k); else if (e->is_curved()) { if (e->is_triangle()) for (unsigned int k = 0; k < e->get_nvert(); k++) o[k] = oo; else for (unsigned int k = 0; k < e->get_nvert(); k++) o[k] = H2D_GET_H_ORDER(oo); } double3* pt; int np; double* x; double* y; if (show_edge_orders || e->is_curved()) { refmap.set_quad_2d(&quad_ord); refmap.set_active_element(e); x = refmap.get_phys_x(1); y = refmap.get_phys_y(1); pt = quad_ord.get_points(1, e->get_mode()); np = quad_ord.get_num_points(1, e->get_mode()); } else { refmap.set_quad_2d(&quad_ord_simple); refmap.set_active_element(e); x = refmap.get_phys_x(1); y = refmap.get_phys_y(1); pt = quad_ord_simple.get_points(1, e->get_mode()); np = quad_ord_simple.get_num_points(1, e->get_mode()); } int id[80]; assert(np <= 80); int mode = e->get_mode(); if (e->is_quad()) { o[4] = H2D_GET_H_ORDER(oo); o[5] = H2D_GET_V_ORDER(oo); } if (show_edge_orders || e->is_curved()) { make_vert(lvert[label_count], x[0], y[0], o[4]); for (int i = 1; i < np; i++) make_vert(id[i - 1], x[i], y[i], o[(int)pt[i][2]]); for (int i = 0; i < num_elem[mode][1]; i++) this->add_triangle(id[ord_elem[mode][1][i][0]], id[ord_elem[mode][1][i][1]], id[ord_elem[mode][1][i][2]], e->marker); for (int i = 0; i < num_edge[mode][1]; i++) { if (e->en[ord_edge[mode][1][i][2]]->bnd || (y[ord_edge[mode][1][i][0] + 1] < y[ord_edge[mode][1][i][1] + 1]) || ((y[ord_edge[mode][1][i][0] + 1] == y[ord_edge[mode][1][i][1] + 1]) && (x[ord_edge[mode][1][i][0] + 1] < x[ord_edge[mode][1][i][1] + 1]))) { add_edge(id[ord_edge[mode][1][i][0]], id[ord_edge[mode][1][i][1]], e->en[ord_edge[mode][1][i][2]]->marker); } } } else { make_vert(lvert[label_count], x[0], y[0], o[4]); for (int i = 1; i < np; i++) make_vert(id[i - 1], x[i], y[i], o[(int)pt[i][2]]); for (int i = 0; i < num_elem_simple[mode][1]; i++) this->add_triangle(id[ord_elem_simple[mode][1][i][0]], id[ord_elem_simple[mode][1][i][1]], id[ord_elem_simple[mode][1][i][2]], e->marker); for (int i = 0; i < num_edge_simple[mode][1]; i++) add_edge(id[ord_edge_simple[mode][1][i][0]], id[ord_edge_simple[mode][1][i][1]], e->en[ord_edge_simple[mode][1][i][2]]->marker); } double xmin = 1e100, ymin = 1e100, xmax = -1e100, ymax = -1e100; for (unsigned int k = 0; k < e->get_nvert(); k++) { if (e->vn[k]->x < xmin) xmin = e->vn[k]->x; if (e->vn[k]->x > xmax) xmax = e->vn[k]->x; if (e->vn[k]->y < ymin) ymin = e->vn[k]->y; if (e->vn[k]->y > ymax) ymax = e->vn[k]->y; } lbox[label_count][0] = xmax - xmin; lbox[label_count][1] = ymax - ymin; ltext[label_count++] = labels[o[4]][o[5]]; }
void Linearizer::process_triangle(int iv0, int iv1, int iv2, int level, scalar* val, double* phx, double* phy, int* idx) { double midval[3][3]; if (level < LIN_MAX_LEVEL) { int i; if (!(level & 1)) { // obtain solution values sln->set_quad_order(1, item); val = sln->get_values(ia, ib); if (auto_max) for (i = 0; i < lin_np_tri[1]; i++) { double v = getval(i); if (finite(v) && fabs(v) > max) max = fabs(v); } // obtain physical element coordinates if (curved || disp) { RefMap* refmap = sln->get_refmap(); phx = refmap->get_phys_x(1); phy = refmap->get_phys_y(1); if (disp) { xdisp->force_transform(sln); ydisp->force_transform(sln); xdisp->set_quad_order(1, FN_VAL); ydisp->set_quad_order(1, FN_VAL); scalar* dx = xdisp->get_fn_values(); scalar* dy = ydisp->get_fn_values(); for (i = 0; i < lin_np_tri[1]; i++) { phx[i] += dmult*realpart(dx[i]); phy[i] += dmult*realpart(dy[i]); } } } idx = tri_indices[0]; } // obtain linearized values and coordinates at the midpoints for (i = 0; i < 3; i++) { midval[i][0] = (verts[iv0][i] + verts[iv1][i])*0.5; midval[i][1] = (verts[iv1][i] + verts[iv2][i])*0.5; midval[i][2] = (verts[iv2][i] + verts[iv0][i])*0.5; }; // determine whether or not to split the element bool split; if (eps >= 1.0) { // if eps > 1, the user wants a fixed number of refinements (no adaptivity) split = (level < eps); } else { if (!auto_max && fabs(verts[iv0][2]) > max && fabs(verts[iv1][2]) > max && fabs(verts[iv2][2]) > max) { // do not split if the whole triangle is above the specified maximum value split = false; } else { // calculate the approximate error of linearizing the normalized solution double err = fabs(getval(idx[0]) - midval[2][0]) + fabs(getval(idx[1]) - midval[2][1]) + fabs(getval(idx[2]) - midval[2][2]); split = !finite(err) || err > max*3*eps; } // do the same for the curvature if (!split && (curved || disp)) { for (i = 0; i < 3; i++) if (sqr(phx[idx[i]] - midval[0][i]) + sqr(phy[idx[i]] - midval[1][i]) > sqr(cmax*1.5e-3)) { split = true; break; } } // do extra tests at level 0, so as not to miss some functions with zero error at edge midpoints if (level == 0 && !split) { split = (fabs(getval(8) - 0.5*(midval[2][0] + midval[2][1])) + fabs(getval(9) - 0.5*(midval[2][1] + midval[2][2])) + fabs(getval(4) - 0.5*(midval[2][2] + midval[2][0]))) > max*3*eps; } } // split the triangle if the error is too large, otherwise produce a linear triangle if (split) { if (curved || disp) for (i = 0; i < 3; i++) { midval[0][i] = phx[idx[i]]; midval[1][i] = phy[idx[i]]; } // obtain mid-edge vertices int mid0 = get_vertex(iv0, iv1, midval[0][0], midval[1][0], getval(idx[0])); int mid1 = get_vertex(iv1, iv2, midval[0][1], midval[1][1], getval(idx[1])); int mid2 = get_vertex(iv2, iv0, midval[0][2], midval[1][2], getval(idx[2])); // recur to sub-elements sln->push_transform(0); process_triangle(iv0, mid0, mid2, level+1, val, phx, phy, tri_indices[1]); sln->pop_transform(); sln->push_transform(1); process_triangle(mid0, iv1, mid1, level+1, val, phx, phy, tri_indices[2]); sln->pop_transform(); sln->push_transform(2); process_triangle(mid2, mid1, iv2, level+1, val, phx, phy, tri_indices[3]); sln->pop_transform(); sln->push_transform(3); process_triangle(mid1, mid2, mid0, level+1, val, phx, phy, tri_indices[4]); sln->pop_transform(); return; } } // no splitting: output a linear triangle add_triangle(iv0, iv1, iv2); }
void Linearizer::process_quad(int iv0, int iv1, int iv2, int iv3, int level, scalar* val, double* phx, double* phy, int* idx) { double midval[3][5]; // try not to split through the vertex with the largest value int a = (verts[iv0][2] > verts[iv1][2]) ? iv0 : iv1; int b = (verts[iv2][2] > verts[iv3][2]) ? iv2 : iv3; a = (verts[a][2] > verts[b][2]) ? a : b; int flip = (a == iv1 || a == iv3) ? 1 : 0; if (level < LIN_MAX_LEVEL) { int i; if (!(level & 1)) // this is an optimization: do the following only every other time { // obtain solution values sln->set_quad_order(1, item); val = sln->get_values(ia, ib); if (auto_max) for (i = 0; i < lin_np_quad[1]; i++) { double v = getval(i); if (finite(v) && fabs(v) > max) max = fabs(v); } // obtain physical element coordinates if (curved || disp) { RefMap* refmap = sln->get_refmap(); phx = refmap->get_phys_x(1); phy = refmap->get_phys_y(1); if (disp) { xdisp->force_transform(sln); ydisp->force_transform(sln); xdisp->set_quad_order(1, FN_VAL); ydisp->set_quad_order(1, FN_VAL); scalar* dx = xdisp->get_fn_values(); scalar* dy = ydisp->get_fn_values(); for (i = 0; i < lin_np_quad[1]; i++) { phx[i] += dmult*realpart(dx[i]); phy[i] += dmult*realpart(dy[i]); } } } idx = quad_indices[0]; } // obtain linearized values and coordinates at the midpoints for (i = 0; i < 3; i++) { midval[i][0] = (verts[iv0][i] + verts[iv1][i]) * 0.5; midval[i][1] = (verts[iv1][i] + verts[iv2][i]) * 0.5; midval[i][2] = (verts[iv2][i] + verts[iv3][i]) * 0.5; midval[i][3] = (verts[iv3][i] + verts[iv0][i]) * 0.5; midval[i][4] = (midval[i][0] + midval[i][2]) * 0.5; }; // the value of the middle point is not the average of the four vertex values, since quad == 2 triangles midval[2][4] = flip ? (verts[iv0][2] + verts[iv2][2]) * 0.5 : (verts[iv1][2] + verts[iv3][2]) * 0.5; // determine whether or not to split the element int split; if (eps >= 1.0) { // if eps > 1, the user wants a fixed number of refinements (no adaptivity) split = (level < eps) ? 3 : 0; } else { if (!auto_max && fabs(verts[iv0][2]) > max && fabs(verts[iv1][2]) > max && fabs(verts[iv2][2]) > max && fabs(verts[iv3][2]) > max) { // do not split if the whole quad is above the specified maximum value split = 0; } else { // calculate the approximate error of linearizing the normalized solution double herr = fabs(getval(idx[1]) - midval[2][1]) + fabs(getval(idx[3]) - midval[2][3]); double verr = fabs(getval(idx[0]) - midval[2][0]) + fabs(getval(idx[2]) - midval[2][2]); double err = fabs(getval(idx[4]) - midval[2][4]) + herr + verr; split = (!finite(err) || err > max*4*eps) ? 3 : 0; // decide whether to split horizontally or vertically only if (level > 0 && split) if (herr > 5*verr) split = 1; // h-split else if (verr > 5*herr) split = 2; // v-split } // also decide whether to split because of the curvature if (split != 3 && (curved || disp)) { double cm2 = sqr(cmax*5e-4); if (sqr(phx[idx[1]] - midval[0][1]) + sqr(phy[idx[1]] - midval[1][1]) > cm2 || sqr(phx[idx[3]] - midval[0][3]) + sqr(phy[idx[3]] - midval[1][3]) > cm2) split |= 1; if (sqr(phx[idx[0]] - midval[0][0]) + sqr(phy[idx[0]] - midval[1][0]) > cm2 || sqr(phx[idx[2]] - midval[0][2]) + sqr(phy[idx[2]] - midval[1][2]) > cm2) split |= 2; /*for (i = 0; i < 5; i++) if (sqr(phx[idx[i]] - midval[0][i]) + sqr(phy[idx[i]] - midval[1][i]) > sqr(cmax*1e-3)) { split = 1; break; }*/ } // do extra tests at level 0, so as not to miss some functions with zero error at edge midpoints if (level == 0 && !split) { split = ((fabs(getval(13) - 0.5*(midval[2][0] + midval[2][1])) + fabs(getval(17) - 0.5*(midval[2][1] + midval[2][2])) + fabs(getval(20) - 0.5*(midval[2][2] + midval[2][3])) + fabs(getval(9) - 0.5*(midval[2][3] + midval[2][0]))) > max*4*eps) ? 3 : 0; } } // split the quad if the error is too large, otherwise produce two linear triangles if (split) { if (curved || disp) for (i = 0; i < 5; i++) { midval[0][i] = phx[idx[i]]; midval[1][i] = phy[idx[i]]; } // obtain mid-edge and mid-element vertices int mid0, mid1, mid2, mid3, mid4; if (split != 1) mid0 = get_vertex(iv0, iv1, midval[0][0], midval[1][0], getval(idx[0])); if (split != 2) mid1 = get_vertex(iv1, iv2, midval[0][1], midval[1][1], getval(idx[1])); if (split != 1) mid2 = get_vertex(iv2, iv3, midval[0][2], midval[1][2], getval(idx[2])); if (split != 2) mid3 = get_vertex(iv3, iv0, midval[0][3], midval[1][3], getval(idx[3])); if (split == 3) mid4 = get_vertex(mid0, mid2, midval[0][4], midval[1][4], getval(idx[4])); // recur to sub-elements if (split == 3) { sln->push_transform(0); process_quad(iv0, mid0, mid4, mid3, level+1, val, phx, phy, quad_indices[1]); sln->pop_transform(); sln->push_transform(1); process_quad(mid0, iv1, mid1, mid4, level+1, val, phx, phy, quad_indices[2]); sln->pop_transform(); sln->push_transform(2); process_quad(mid4, mid1, iv2, mid2, level+1, val, phx, phy, quad_indices[3]); sln->pop_transform(); sln->push_transform(3); process_quad(mid3, mid4, mid2, iv3, level+1, val, phx, phy, quad_indices[4]); sln->pop_transform(); } else if (split == 1) // h-split { sln->push_transform(4); process_quad(iv0, iv1, mid1, mid3, level+1, val, phx, phy, quad_indices[5]); sln->pop_transform(); sln->push_transform(5); process_quad(mid3, mid1, iv2, iv3, level+1, val, phx, phy, quad_indices[6]); sln->pop_transform(); } else // v-split { sln->push_transform(6); process_quad(iv0, mid0, mid2, iv3, level+1, val, phx, phy, quad_indices[7]); sln->pop_transform(); sln->push_transform(7); process_quad(mid0, iv1, iv2, mid2, level+1, val, phx, phy, quad_indices[8]); sln->pop_transform(); } return; } } // output two linear triangles, if (!flip) { add_triangle(iv3, iv0, iv1); add_triangle(iv1, iv2, iv3); } else { add_triangle(iv0, iv1, iv2); add_triangle(iv2, iv3, iv0); } }
void Orderizer::process_solution(Space* space) { // sanity check if (space == NULL) error("Space is NULL in Orderizer:process_solution()."); if (!space->is_up_to_date()) error("The space is not up to date."); int type = 1; nv = nt = ne = nl = 0; del_slot = -1; // estimate the required number of vertices and triangles Mesh* mesh = space->get_mesh(); if (mesh == NULL) { error("Mesh is NULL in Orderizer:process_solution()."); } int nn = mesh->get_num_active_elements(); int ev = 77 * nn, et = 64 * nn, ee = 16 * nn, el = nn + 10; // reuse or allocate vertex, triangle and edge arrays lin_init_array(verts, double3, cv, ev); lin_init_array(tris, int3, ct, et); lin_init_array(edges, int3, ce, ee); lin_init_array(lvert, int, cl1, el); lin_init_array(ltext, char*, cl2, el); lin_init_array(lbox, double2, cl3, el); info = NULL; int oo, o[6]; RefMap refmap; refmap.set_quad_2d(&quad_ord); // make a mesh illustrating the distribution of polynomial orders over the space Element* e; for_all_active_elements(e, mesh) { oo = o[4] = o[5] = space->get_element_order(e->id); for (unsigned int k = 0; k < e->nvert; k++) o[k] = space->get_edge_order(e, k); refmap.set_active_element(e); double* x = refmap.get_phys_x(type); double* y = refmap.get_phys_y(type); double3* pt = quad_ord.get_points(type); int np = quad_ord.get_num_points(type); int id[80]; assert(np <= 80); #define make_vert(index, x, y, val) \ { (index) = add_vertex(); \ verts[index][0] = (x); \ verts[index][1] = (y); \ verts[index][2] = (val); } int mode = e->get_mode(); if (e->is_quad()) { o[4] = H2D_GET_H_ORDER(oo); o[5] = H2D_GET_V_ORDER(oo); } make_vert(lvert[nl], x[0], y[0], o[4]); for (int i = 1; i < np; i++) make_vert(id[i-1], x[i], y[i], o[(int) pt[i][2]]); for (int i = 0; i < num_elem[mode][type]; i++) add_triangle(id[ord_elem[mode][type][i][0]], id[ord_elem[mode][type][i][1]], id[ord_elem[mode][type][i][2]]); for (int i = 0; i < num_edge[mode][type]; i++) { if (e->en[ord_edge[mode][type][i][2]]->bnd || (y[ord_edge[mode][type][i][0] + 1] < y[ord_edge[mode][type][i][1] + 1]) || ((y[ord_edge[mode][type][i][0] + 1] == y[ord_edge[mode][type][i][1] + 1]) && (x[ord_edge[mode][type][i][0] + 1] < x[ord_edge[mode][type][i][1] + 1]))) { add_edge(id[ord_edge[mode][type][i][0]], id[ord_edge[mode][type][i][1]], 0); } } double xmin = 1e100, ymin = 1e100, xmax = -1e100, ymax = -1e100; for (unsigned int k = 0; k < e->nvert; k++) { if (e->vn[k]->x < xmin) xmin = e->vn[k]->x; if (e->vn[k]->x > xmax) xmax = e->vn[k]->x; if (e->vn[k]->y < ymin) ymin = e->vn[k]->y; if (e->vn[k]->y > ymax) ymax = e->vn[k]->y; } lbox[nl][0] = xmax - xmin; lbox[nl][1] = ymax - ymin; ltext[nl++] = labels[o[4]][o[5]]; }
void Liveness::emptify(RefMap &M) { for (auto I = M.begin(), E = M.end(); I != E; ) I = I->second.empty() ? M.erase(I) : std::next(I); }
void Liveness::traverse(MachineBasicBlock *B, RefMap &LiveIn) { // The LiveIn map, for each (physical) register, contains the set of live // reaching defs of that register that are live on entry to the associated // block. // The summary of the traversal algorithm: // // R is live-in in B, if there exists a U(R), such that rdef(R) dom B // and (U \in IDF(B) or B dom U). // // for (C : children) { // LU = {} // traverse(C, LU) // LiveUses += LU // } // // LiveUses -= Defs(B); // LiveUses += UpwardExposedUses(B); // for (C : IIDF[B]) // for (U : LiveUses) // if (Rdef(U) dom C) // C.addLiveIn(U) // // Go up the dominator tree (depth-first). MachineDomTreeNode *N = MDT.getNode(B); for (auto I : *N) { RefMap L; MachineBasicBlock *SB = I->getBlock(); traverse(SB, L); for (auto S : L) LiveIn[S.first].insert(S.second.begin(), S.second.end()); } if (Trace) { dbgs() << LLVM_FUNCTION_NAME << " in BB#" << B->getNumber() << " after recursion into"; for (auto I : *N) dbgs() << ' ' << I->getBlock()->getNumber(); dbgs() << "\n LiveIn: " << Print<RefMap>(LiveIn, DFG); dbgs() << "\n Local: " << Print<RegisterSet>(LiveMap[B], DFG) << '\n'; } // Add phi uses that are live on exit from this block. RefMap &PUs = PhiLOX[B]; for (auto S : PUs) LiveIn[S.first].insert(S.second.begin(), S.second.end()); if (Trace) { dbgs() << "after LOX\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterSet>(LiveMap[B], DFG) << '\n'; } // Stop tracking all uses defined in this block: erase those records // where the reaching def is located in B and which cover all reached // uses. auto Copy = LiveIn; LiveIn.clear(); for (auto I : Copy) { auto &Defs = LiveIn[I.first]; NodeSet Rest; for (auto R : I.second) { auto DA = DFG.addr<DefNode*>(R); RegisterRef DDR = DA.Addr->getRegRef(); NodeAddr<InstrNode*> IA = DA.Addr->getOwner(DFG); NodeAddr<BlockNode*> BA = IA.Addr->getOwner(DFG); // Defs from a different block need to be preserved. Defs from this // block will need to be processed further, except for phi defs, the // liveness of which is handled through the PhiLON/PhiLOX maps. if (B != BA.Addr->getCode()) Defs.insert(R); else { bool IsPreserving = DA.Addr->getFlags() & NodeAttrs::Preserving; if (IA.Addr->getKind() != NodeAttrs::Phi && !IsPreserving) { bool Covering = RAI.covers(DDR, I.first); NodeId U = DA.Addr->getReachedUse(); while (U && Covering) { auto DUA = DFG.addr<UseNode*>(U); RegisterRef Q = DUA.Addr->getRegRef(); Covering = RAI.covers(DA.Addr->getRegRef(), Q); U = DUA.Addr->getSibling(); } if (!Covering) Rest.insert(R); } } } // Non-covering defs from B. for (auto R : Rest) { auto DA = DFG.addr<DefNode*>(R); RegisterRef DRR = DA.Addr->getRegRef(); RegisterSet RRs; for (NodeAddr<DefNode*> TA : getAllReachingDefs(DA)) { NodeAddr<InstrNode*> IA = TA.Addr->getOwner(DFG); NodeAddr<BlockNode*> BA = IA.Addr->getOwner(DFG); // Preserving defs do not count towards covering. if (!(TA.Addr->getFlags() & NodeAttrs::Preserving)) RRs.insert(TA.Addr->getRegRef()); if (BA.Addr->getCode() == B) continue; if (RAI.covers(RRs, DRR)) break; Defs.insert(TA.Id); } } } emptify(LiveIn); if (Trace) { dbgs() << "after defs in block\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterSet>(LiveMap[B], DFG) << '\n'; } // Scan the block for upward-exposed uses and add them to the tracking set. for (auto I : DFG.getFunc().Addr->findBlock(B, DFG).Addr->members(DFG)) { NodeAddr<InstrNode*> IA = I; if (IA.Addr->getKind() != NodeAttrs::Stmt) continue; for (NodeAddr<UseNode*> UA : IA.Addr->members_if(DFG.IsUse, DFG)) { RegisterRef RR = UA.Addr->getRegRef(); for (auto D : getAllReachingDefs(UA)) if (getBlockWithRef(D.Id) != B) LiveIn[RR].insert(D.Id); } } if (Trace) { dbgs() << "after uses in block\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterSet>(LiveMap[B], DFG) << '\n'; } // Phi uses should not be propagated up the dominator tree, since they // are not dominated by their corresponding reaching defs. auto &Local = LiveMap[B]; auto &LON = PhiLON[B]; for (auto R : LON) Local.insert(R.first); if (Trace) { dbgs() << "after phi uses in block\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterSet>(Local, DFG) << '\n'; } for (auto C : IIDF[B]) { auto &LiveC = LiveMap[C]; for (auto S : LiveIn) for (auto R : S.second) if (MDT.properlyDominates(getBlockWithRef(R), C)) LiveC.insert(S.first); } }
double KellyTypeAdapt::calc_err_internal(Hermes::vector<Solution *> slns, Hermes::vector<double>* component_errors, unsigned int error_flags) { int n = slns.size(); error_if (n != this->num, "Wrong number of solutions."); TimePeriod tmr; for (int i = 0; i < n; i++) { this->sln[i] = slns[i]; sln[i]->set_quad_2d(&g_quad_2d_std); } have_coarse_solutions = true; WeakForm::Stage stage; num_act_elems = 0; for (int i = 0; i < num; i++) { stage.meshes.push_back(sln[i]->get_mesh()); stage.fns.push_back(sln[i]); num_act_elems += stage.meshes[i]->get_num_active_elements(); int max = stage.meshes[i]->get_max_element_id(); if (errors[i] != NULL) delete [] errors[i]; errors[i] = new double[max]; memset(errors[i], 0.0, sizeof(double) * max); } /* for (unsigned int i = 0; i < error_estimators_vol.size(); i++) trset.insert(error_estimators_vol[i].ext.begin(), error_estimators_vol[i].ext.end()); for (unsigned int i = 0; i < error_estimators_surf.size(); i++) trset.insert(error_estimators_surf[i].ext.begin(), error_estimators_surf[i].ext.end()); */ double total_norm = 0.0; bool calc_norm = false; if ((error_flags & HERMES_ELEMENT_ERROR_MASK) == HERMES_ELEMENT_ERROR_REL || (error_flags & HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_REL) calc_norm = true; double *norms = NULL; if (calc_norm) { norms = new double[num]; memset(norms, 0.0, num * sizeof(double)); } double *errors_components = new double[num]; memset(errors_components, 0.0, num * sizeof(double)); this->errors_squared_sum = 0.0; double total_error = 0.0; bool bnd[4]; // FIXME: magic number - maximal possible number of element surfaces SurfPos surf_pos[4]; Element **ee; Traverse trav; // Reset the e->visited status of each element of each mesh (most likely it will be set to true from // the latest assembling procedure). if (ignore_visited_segments) { for (int i = 0; i < num; i++) { Element* e; for_all_active_elements(e, stage.meshes[i]) e->visited = false; } } //WARNING: AD HOC debugging parameter. bool multimesh = false; // Begin the multimesh traversal. trav.begin(num, &(stage.meshes.front()), &(stage.fns.front())); while ((ee = trav.get_next_state(bnd, surf_pos)) != NULL) { // Go through all solution components. for (int i = 0; i < num; i++) { if (ee[i] == NULL) continue; // Set maximum integration order for use in integrals, see limit_order() update_limit_table(ee[i]->get_mode()); RefMap *rm = sln[i]->get_refmap(); double err = 0.0; // Go through all volumetric error estimators. for (unsigned int iest = 0; iest < error_estimators_vol.size(); iest++) { // Skip current error estimator if it is assigned to a different component or geometric area // different from that of the current active element. if (error_estimators_vol[iest]->i != i) continue; /* if (error_estimators_vol[iest].area != ee[i]->marker) continue; */ else if (error_estimators_vol[iest]->area != HERMES_ANY) continue; err += eval_volumetric_estimator(error_estimators_vol[iest], rm); } // Go through all surface error estimators (includes both interface and boundary est's). for (unsigned int iest = 0; iest < error_estimators_surf.size(); iest++) { if (error_estimators_surf[iest]->i != i) continue; for (int isurf = 0; isurf < ee[i]->get_num_surf(); isurf++) { /* if (error_estimators_surf[iest].area > 0 && error_estimators_surf[iest].area != surf_pos[isurf].marker) continue; */ if (bnd[isurf]) // Boundary { if (error_estimators_surf[iest]->area == H2D_DG_INNER_EDGE) continue; /* if (boundary_markers_conversion.get_internal_marker(error_estimators_surf[iest].area) < 0 && error_estimators_surf[iest].area != HERMES_ANY) continue; */ err += eval_boundary_estimator(error_estimators_surf[iest], rm, surf_pos); } else // Interface { if (error_estimators_surf[iest]->area != H2D_DG_INNER_EDGE) continue; /* BEGIN COPY FROM DISCRETE_PROBLEM.CPP */ // 5 is for bits per page in the array. LightArray<NeighborSearch*> neighbor_searches(5); unsigned int num_neighbors = 0; DiscreteProblem::NeighborNode* root; int ns_index; dp.min_dg_mesh_seq = 0; for(int j = 0; j < num; j++) if(stage.meshes[j]->get_seq() < dp.min_dg_mesh_seq || j == 0) dp.min_dg_mesh_seq = stage.meshes[j]->get_seq(); ns_index = stage.meshes[i]->get_seq() - dp.min_dg_mesh_seq; // = 0 for single mesh // Determine the minimum mesh seq in this stage. if (multimesh) { // Initialize the NeighborSearches. dp.init_neighbors(neighbor_searches, stage, isurf); // Create a multimesh tree; root = new DiscreteProblem::NeighborNode(NULL, 0); dp.build_multimesh_tree(root, neighbor_searches); // Update all NeighborSearches according to the multimesh tree. // After this, all NeighborSearches in neighbor_searches should have the same count // of neighbors and proper set of transformations // for the central and the neighbor element(s) alike. // Also check that every NeighborSearch has the same number of neighbor elements. for(unsigned int j = 0; j < neighbor_searches.get_size(); j++) if(neighbor_searches.present(j)) { NeighborSearch* ns = neighbor_searches.get(j); dp.update_neighbor_search(ns, root); if(num_neighbors == 0) num_neighbors = ns->n_neighbors; if(ns->n_neighbors != num_neighbors) error("Num_neighbors of different NeighborSearches not matching in KellyTypeAdapt::calc_err_internal."); } } else { NeighborSearch *ns = new NeighborSearch(ee[i], stage.meshes[i]); ns->original_central_el_transform = stage.fns[i]->get_transform(); ns->set_active_edge(isurf); ns->clear_initial_sub_idx(); num_neighbors = ns->n_neighbors; neighbor_searches.add(ns, ns_index); } // Go through all segments of the currently processed interface (segmentation is caused // by hanging nodes on the other side of the interface). for (unsigned int neighbor = 0; neighbor < num_neighbors; neighbor++) { if (ignore_visited_segments) { bool processed = true; for(unsigned int j = 0; j < neighbor_searches.get_size(); j++) if(neighbor_searches.present(j)) if(!neighbor_searches.get(j)->neighbors.at(neighbor)->visited) { processed = false; break; } if (processed) continue; } // Set the active segment in all NeighborSearches for(unsigned int j = 0; j < neighbor_searches.get_size(); j++) if(neighbor_searches.present(j)) { neighbor_searches.get(j)->active_segment = neighbor; neighbor_searches.get(j)->neighb_el = neighbor_searches.get(j)->neighbors[neighbor]; neighbor_searches.get(j)->neighbor_edge = neighbor_searches.get(j)->neighbor_edges[neighbor]; } // Push all the necessary transformations to all functions of this stage. // The important thing is that the transformations to the current subelement are already there. // Also store the current neighbor element and neighbor edge in neighb_el, neighbor_edge. if (multimesh) { for(unsigned int fns_i = 0; fns_i < stage.fns.size(); fns_i++) for(unsigned int trf_i = 0; trf_i < neighbor_searches.get(stage.meshes[fns_i]->get_seq() - dp.min_dg_mesh_seq)->central_n_trans[neighbor]; trf_i++) stage.fns[fns_i]->push_transform(neighbor_searches.get(stage.meshes[fns_i]->get_seq() - dp.min_dg_mesh_seq)->central_transformations[neighbor][trf_i]); } else { // Push the transformations only to the solution on the current mesh for(unsigned int trf_i = 0; trf_i < neighbor_searches.get(ns_index)->central_n_trans[neighbor]; trf_i++) stage.fns[i]->push_transform(neighbor_searches.get(ns_index)->central_transformations[neighbor][trf_i]); } /* END COPY FROM DISCRETE_PROBLEM.CPP */ rm->force_transform(this->sln[i]->get_transform(), this->sln[i]->get_ctm()); // The estimate is multiplied by 0.5 in order to distribute the error equally onto // the two neighboring elements. double central_err = 0.5 * eval_interface_estimator(error_estimators_surf[iest], rm, surf_pos, neighbor_searches, ns_index); double neighb_err = central_err; // Scale the error estimate by the scaling function dependent on the element diameter // (use the central element's diameter). if (use_aposteriori_interface_scaling && interface_scaling_fns[i]) central_err *= interface_scaling_fns[i](ee[i]->get_diameter()); // In the case this edge will be ignored when calculating the error for the element on // the other side, add the now computed error to that element as well. if (ignore_visited_segments) { Element *neighb = neighbor_searches.get(i)->neighb_el; // Scale the error estimate by the scaling function dependent on the element diameter // (use the diameter of the element on the other side). if (use_aposteriori_interface_scaling && interface_scaling_fns[i]) neighb_err *= interface_scaling_fns[i](neighb->get_diameter()); errors_components[i] += central_err + neighb_err; total_error += central_err + neighb_err; errors[i][ee[i]->id] += central_err; errors[i][neighb->id] += neighb_err; } else err += central_err; /* BEGIN COPY FROM DISCRETE_PROBLEM.CPP */ // Clear the transformations from the RefMaps and all functions. if (multimesh) for(unsigned int fns_i = 0; fns_i < stage.fns.size(); fns_i++) stage.fns[fns_i]->set_transform(neighbor_searches.get(stage.meshes[fns_i]->get_seq() - dp.min_dg_mesh_seq)->original_central_el_transform); else stage.fns[i]->set_transform(neighbor_searches.get(ns_index)->original_central_el_transform); rm->set_transform(neighbor_searches.get(ns_index)->original_central_el_transform); /* END COPY FROM DISCRETE_PROBLEM.CPP */ } /* BEGIN COPY FROM DISCRETE_PROBLEM.CPP */ if (multimesh) // Delete the multimesh tree; delete root; // Delete the neighbor_searches array. for(unsigned int j = 0; j < neighbor_searches.get_size(); j++) if(neighbor_searches.present(j)) delete neighbor_searches.get(j); /* END COPY FROM DISCRETE_PROBLEM.CPP */ } } } if (calc_norm) { double nrm = eval_solution_norm(error_form[i][i], rm, sln[i]); norms[i] += nrm; total_norm += nrm; } errors_components[i] += err; total_error += err; errors[i][ee[i]->id] += err; ee[i]->visited = true; } } trav.finish(); // Store the calculation for each solution component separately. if(component_errors != NULL) { component_errors->clear(); for (int i = 0; i < num; i++) { if((error_flags & HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_ABS) component_errors->push_back(sqrt(errors_components[i])); else if ((error_flags & HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_REL) component_errors->push_back(sqrt(errors_components[i]/norms[i])); else { error("Unknown total error type (0x%x).", error_flags & HERMES_TOTAL_ERROR_MASK); return -1.0; } } } tmr.tick(); error_time = tmr.accumulated(); // Make the error relative if needed. if ((error_flags & HERMES_ELEMENT_ERROR_MASK) == HERMES_ELEMENT_ERROR_REL) { for (int i = 0; i < num; i++) { Element* e; for_all_active_elements(e, stage.meshes[i]) errors[i][e->id] /= norms[i]; } } this->errors_squared_sum = total_error; // Element error mask is used here, because this variable is used in the adapt() // function, where the processed error (sum of errors of processed element errors) // is matched to this variable. if ((error_flags & HERMES_TOTAL_ERROR_MASK) == HERMES_ELEMENT_ERROR_REL) errors_squared_sum /= total_norm; // Prepare an ordered list of elements according to an error. fill_regular_queue(&(stage.meshes.front())); have_errors = true; if (calc_norm) delete [] norms; delete [] errors_components; // Return error value. if ((error_flags & HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_ABS) return sqrt(total_error); else if ((error_flags & HERMES_TOTAL_ERROR_MASK) == HERMES_TOTAL_ERROR_REL) return sqrt(total_error / total_norm); else { error("Unknown total error type (0x%x).", error_flags & HERMES_TOTAL_ERROR_MASK); return -1.0; } }
void Linearizer::process_quad(MeshFunction<double>** fns, int iv0, int iv1, int iv2, int iv3, int level, double* val, double* phx, double* phy, int* idx, bool curved) { double midval[3][5]; // try not to split through the vertex with the largest value int a = (verts[iv0][2] > verts[iv1][2]) ? iv0 : iv1; int b = (verts[iv2][2] > verts[iv3][2]) ? iv2 : iv3; a = (verts[a][2] > verts[b][2]) ? a : b; int flip = (a == iv1 || a == iv3) ? 1 : 0; if(level < LinearizerBase::get_max_level(fns[0]->get_active_element(), fns[0]->get_fn_order(), fns[0]->get_mesh())) { int i; if(!(level & 1)) // this is an optimization: do the following only every other time { // obtain solution values fns[0]->set_quad_order(1, item); val = fns[0]->get_values(component, value_type); if(auto_max) for (i = 0; i < lin_np_quad[1]; i++) { double v = val[i]; if(finite(v) && fabs(v) > max) #pragma omp critical(max) if(finite(v) && fabs(v) > max) max = fabs(v); } // This is just to make some sense. if(fabs(max) < Hermes::HermesSqrtEpsilon) max = Hermes::HermesSqrtEpsilon; idx = quad_indices[0]; if(curved) { RefMap* refmap = fns[0]->get_refmap(); phx = refmap->get_phys_x(1); phy = refmap->get_phys_y(1); double* dx = nullptr; double* dy = nullptr; if(this->xdisp != nullptr) fns[1]->set_quad_order(1, H2D_FN_VAL); if(this->ydisp != nullptr) fns[this->xdisp == nullptr ? 1 : 2]->set_quad_order(1, H2D_FN_VAL); if(this->xdisp != nullptr) dx = fns[1]->get_fn_values(); if(this->ydisp != nullptr) dy = fns[this->xdisp == nullptr ? 1 : 2]->get_fn_values(); for (i = 0; i < lin_np_quad[1]; i++) { if(this->xdisp != nullptr) phx[i] += dmult*dx[i]; if(this->ydisp != nullptr) phy[i] += dmult*dy[i]; } } } // obtain linearized values and coordinates at the midpoints for (i = 0; i < 3; i++) { midval[i][0] = (verts[iv0][i] + verts[iv1][i]) * 0.5; midval[i][1] = (verts[iv1][i] + verts[iv2][i]) * 0.5; midval[i][2] = (verts[iv2][i] + verts[iv3][i]) * 0.5; midval[i][3] = (verts[iv3][i] + verts[iv0][i]) * 0.5; midval[i][4] = (midval[i][0] + midval[i][2]) * 0.5; }; // the value of the middle point is not the average of the four vertex values, since quad == 2 triangles midval[2][4] = flip ? (verts[iv0][2] + verts[iv2][2]) * 0.5 : (verts[iv1][2] + verts[iv3][2]) * 0.5; // determine whether or not to split the element int split; if(eps >= 1.0) { // if eps > 1, the user wants a fixed number of refinements (no adaptivity) split = (level < eps) ? 3 : 0; } else { if(!auto_max && fabs(verts[iv0][2]) > max && fabs(verts[iv1][2]) > max && fabs(verts[iv2][2]) > max && fabs(verts[iv3][2]) > max) { // do not split if the whole quad is above the specified maximum value split = 0; } else { // calculate the approximate error of linearizing the normalized solution double herr = fabs(val[idx[1]] - midval[2][1]) + fabs(val[idx[3]] - midval[2][3]); double verr = fabs(val[idx[0]] - midval[2][0]) + fabs(val[idx[2]] - midval[2][2]); double err = fabs(val[idx[4]] - midval[2][4]) + herr + verr; split = (!finite(err) || err > max*4*eps) ? 3 : 0; // decide whether to split horizontally or vertically only if(level > 0 && split) { if(herr > 5*verr) split = 1; // h-split else if(verr > 5*herr) split = 2; // v-split } } // also decide whether to split because of the curvature if(split != 3 && curved) { double cm2 = sqr(fns[0]->get_active_element()->get_diameter()*this->get_curvature_epsilon()); if(sqr(phx[idx[1]] - midval[0][1]) + sqr(phy[idx[1]] - midval[1][1]) > cm2 || sqr(phx[idx[3]] - midval[0][3]) + sqr(phy[idx[3]] - midval[1][3]) > cm2) split |= 1; if(sqr(phx[idx[0]] - midval[0][0]) + sqr(phy[idx[0]] - midval[1][0]) > cm2 || sqr(phx[idx[2]] - midval[0][2]) + sqr(phy[idx[2]] - midval[1][2]) > cm2) split |= 2; } // do extra tests at level 0, so as not to miss some functions with zero error at edge midpoints if(level == 0 && !split) { split = ((fabs(val[13] - 0.5*(midval[2][0] + midval[2][1])) + fabs(val[17] - 0.5*(midval[2][1] + midval[2][2])) + fabs(val[20] - 0.5*(midval[2][2] + midval[2][3])) + fabs(val[9] - 0.5*(midval[2][3] + midval[2][0]))) > max*4*eps) ? 3 : 0; } } // split the quad if the error is too large, otherwise produce two linear triangles if(split) { if(curved) for (i = 0; i < 5; i++) { midval[0][i] = phx[idx[i]]; midval[1][i] = phy[idx[i]]; } // obtain mid-edge and mid-element vertices int mid0, mid1, mid2, mid3, mid4; if(split != 1) mid0 = get_vertex(iv0, iv1, midval[0][0], midval[1][0], val[idx[0]]); if(split != 2) mid1 = get_vertex(iv1, iv2, midval[0][1], midval[1][1], val[idx[1]]); if(split != 1) mid2 = get_vertex(iv2, iv3, midval[0][2], midval[1][2], val[idx[2]]); if(split != 2) mid3 = get_vertex(iv3, iv0, midval[0][3], midval[1][3], val[idx[3]]); if(split == 3) mid4 = get_vertex(mid0, mid2, midval[0][4], midval[1][4], val[idx[4]]); if(!this->exceptionMessageCaughtInParallelBlock.empty()) return; // recur to sub-elements if(split == 3) { this->push_transforms(fns, 0); process_quad(fns, iv0, mid0, mid4, mid3, level + 1, val, phx, phy, quad_indices[1], curved); this->pop_transforms(fns); this->push_transforms(fns, 1); process_quad(fns, mid0, iv1, mid1, mid4, level + 1, val, phx, phy, quad_indices[2], curved); this->pop_transforms(fns); this->push_transforms(fns, 2); process_quad(fns, mid4, mid1, iv2, mid2, level + 1, val, phx, phy, quad_indices[3], curved); this->pop_transforms(fns); this->push_transforms(fns, 3); process_quad(fns, mid3, mid4, mid2, iv3, level + 1, val, phx, phy, quad_indices[4], curved); this->pop_transforms(fns); } else if(split == 1) // h-split { this->push_transforms(fns, 4); process_quad(fns, iv0, iv1, mid1, mid3, level + 1, val, phx, phy, quad_indices[5], curved); this->pop_transforms(fns); this->push_transforms(fns, 5); process_quad(fns, mid3, mid1, iv2, iv3, level + 1, val, phx, phy, quad_indices[6], curved); this->pop_transforms(fns); } else // v-split { this->push_transforms(fns, 6); process_quad(fns, iv0, mid0, mid2, iv3, level + 1, val, phx, phy, quad_indices[7], curved); this->pop_transforms(fns); this->push_transforms(fns, 7); process_quad(fns, mid0, iv1, iv2, mid2, level + 1, val, phx, phy, quad_indices[8], curved); this->pop_transforms(fns); } return; } } // output two linear triangles, if(!flip) { add_triangle(iv3, iv0, iv1, fns[0]->get_active_element()->marker); add_triangle(iv1, iv2, iv3, fns[0]->get_active_element()->marker); } else { add_triangle(iv0, iv1, iv2, fns[0]->get_active_element()->marker); add_triangle(iv2, iv3, iv0, fns[0]->get_active_element()->marker); } }
void Liveness::traverse(MachineBasicBlock *B, RefMap &LiveIn) { // The LiveIn map, for each (physical) register, contains the set of live // reaching defs of that register that are live on entry to the associated // block. // The summary of the traversal algorithm: // // R is live-in in B, if there exists a U(R), such that rdef(R) dom B // and (U \in IDF(B) or B dom U). // // for (C : children) { // LU = {} // traverse(C, LU) // LiveUses += LU // } // // LiveUses -= Defs(B); // LiveUses += UpwardExposedUses(B); // for (C : IIDF[B]) // for (U : LiveUses) // if (Rdef(U) dom C) // C.addLiveIn(U) // // Go up the dominator tree (depth-first). MachineDomTreeNode *N = MDT.getNode(B); for (auto I : *N) { RefMap L; MachineBasicBlock *SB = I->getBlock(); traverse(SB, L); for (auto S : L) LiveIn[S.first].insert(S.second.begin(), S.second.end()); } if (Trace) { dbgs() << "\n-- BB#" << B->getNumber() << ": " << __func__ << " after recursion into: {"; for (auto I : *N) dbgs() << ' ' << I->getBlock()->getNumber(); dbgs() << " }\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterAggr>(LiveMap[B], DFG) << '\n'; } // Add reaching defs of phi uses that are live on exit from this block. RefMap &PUs = PhiLOX[B]; for (auto &S : PUs) LiveIn[S.first].insert(S.second.begin(), S.second.end()); if (Trace) { dbgs() << "after LOX\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterAggr>(LiveMap[B], DFG) << '\n'; } // The LiveIn map at this point has all defs that are live-on-exit from B, // as if they were live-on-entry to B. First, we need to filter out all // defs that are present in this block. Then we will add reaching defs of // all upward-exposed uses. // To filter out the defs, first make a copy of LiveIn, and then re-populate // LiveIn with the defs that should remain. RefMap LiveInCopy = LiveIn; LiveIn.clear(); for (const std::pair<RegisterId,NodeRefSet> &LE : LiveInCopy) { RegisterRef LRef(LE.first); NodeRefSet &NewDefs = LiveIn[LRef.Reg]; // To be filled. const NodeRefSet &OldDefs = LE.second; for (NodeRef OR : OldDefs) { // R is a def node that was live-on-exit auto DA = DFG.addr<DefNode*>(OR.first); NodeAddr<InstrNode*> IA = DA.Addr->getOwner(DFG); NodeAddr<BlockNode*> BA = IA.Addr->getOwner(DFG); if (B != BA.Addr->getCode()) { // Defs from a different block need to be preserved. Defs from this // block will need to be processed further, except for phi defs, the // liveness of which is handled through the PhiLON/PhiLOX maps. NewDefs.insert(OR); continue; } // Defs from this block need to stop the liveness from being // propagated upwards. This only applies to non-preserving defs, // and to the parts of the register actually covered by those defs. // (Note that phi defs should always be preserving.) RegisterAggr RRs(PRI); LRef.Mask = OR.second; if (!DFG.IsPreservingDef(DA)) { assert(!(IA.Addr->getFlags() & NodeAttrs::Phi)); // DA is a non-phi def that is live-on-exit from this block, and // that is also located in this block. LRef is a register ref // whose use this def reaches. If DA covers LRef, then no part // of LRef is exposed upwards.A if (RRs.insert(DA.Addr->getRegRef(DFG)).hasCoverOf(LRef)) continue; } // DA itself was not sufficient to cover LRef. In general, it is // the last in a chain of aliased defs before the exit from this block. // There could be other defs in this block that are a part of that // chain. Check that now: accumulate the registers from these defs, // and if they all together cover LRef, it is not live-on-entry. for (NodeAddr<DefNode*> TA : getAllReachingDefs(DA)) { // DefNode -> InstrNode -> BlockNode. NodeAddr<InstrNode*> ITA = TA.Addr->getOwner(DFG); NodeAddr<BlockNode*> BTA = ITA.Addr->getOwner(DFG); // Reaching defs are ordered in the upward direction. if (BTA.Addr->getCode() != B) { // We have reached past the beginning of B, and the accumulated // registers are not covering LRef. The first def from the // upward chain will be live. // Subtract all accumulated defs (RRs) from LRef. RegisterAggr L(PRI); L.insert(LRef).clear(RRs); assert(!L.empty()); NewDefs.insert({TA.Id,L.begin()->second}); break; } // TA is in B. Only add this def to the accumulated cover if it is // not preserving. if (!(TA.Addr->getFlags() & NodeAttrs::Preserving)) RRs.insert(TA.Addr->getRegRef(DFG)); // If this is enough to cover LRef, then stop. if (RRs.hasCoverOf(LRef)) break; } } } emptify(LiveIn); if (Trace) { dbgs() << "after defs in block\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterAggr>(LiveMap[B], DFG) << '\n'; } // Scan the block for upward-exposed uses and add them to the tracking set. for (auto I : DFG.getFunc().Addr->findBlock(B, DFG).Addr->members(DFG)) { NodeAddr<InstrNode*> IA = I; if (IA.Addr->getKind() != NodeAttrs::Stmt) continue; for (NodeAddr<UseNode*> UA : IA.Addr->members_if(DFG.IsUse, DFG)) { if (UA.Addr->getFlags() & NodeAttrs::Undef) continue; RegisterRef RR = PRI.normalize(UA.Addr->getRegRef(DFG)); for (NodeAddr<DefNode*> D : getAllReachingDefs(UA)) if (getBlockWithRef(D.Id) != B) LiveIn[RR.Reg].insert({D.Id,RR.Mask}); } } if (Trace) { dbgs() << "after uses in block\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterAggr>(LiveMap[B], DFG) << '\n'; } // Phi uses should not be propagated up the dominator tree, since they // are not dominated by their corresponding reaching defs. RegisterAggr &Local = LiveMap[B]; RefMap &LON = PhiLON[B]; for (auto &R : LON) { LaneBitmask M; for (auto P : R.second) M |= P.second; Local.insert(RegisterRef(R.first,M)); } if (Trace) { dbgs() << "after phi uses in block\n"; dbgs() << " LiveIn: " << Print<RefMap>(LiveIn, DFG) << '\n'; dbgs() << " Local: " << Print<RegisterAggr>(Local, DFG) << '\n'; } for (auto C : IIDF[B]) { RegisterAggr &LiveC = LiveMap[C]; for (const std::pair<RegisterId,NodeRefSet> &S : LiveIn) for (auto R : S.second) if (MDT.properlyDominates(getBlockWithRef(R.first), C)) LiveC.insert(RegisterRef(S.first, R.second)); } }
void Vectorizer::process_triangle(int iv0, int iv1, int iv2, int level, scalar* xval, scalar* yval, double* phx, double* phy, int* idx) { if (level < LIN_MAX_LEVEL) { int i; if (!(level & 1)) { // obtain solution values and physical element coordinates xsln->set_quad_order(1, xitem); ysln->set_quad_order(1, yitem); xval = xsln->get_values(xia, xib); yval = ysln->get_values(yia, yib); for (i = 0; i < lin_np_tri[1]; i++) { double m = getmag(i); if (finite(m) && fabs(m) > max) max = fabs(m); } if (curved) { RefMap* refmap = xsln->get_refmap(); phx = refmap->get_phys_x(1); phy = refmap->get_phys_y(1); } idx = tri_indices[0]; } // obtain linearized values and coordinates at the midpoints double midval[4][3]; for (i = 0; i < 4; i++) { midval[i][0] = (verts[iv0][i] + verts[iv1][i])*0.5; midval[i][1] = (verts[iv1][i] + verts[iv2][i])*0.5; midval[i][2] = (verts[iv2][i] + verts[iv0][i])*0.5; }; // determine whether or not to split the element bool split; if (eps >= 1.0) { //if eps > 1, the user wants a fixed number of refinements (no adaptivity) split = (level < eps); } else { // calculate the approximate error of linearizing the normalized solution double err = fabs(getmag(idx[0]) - midmag(0)) + fabs(getmag(idx[1]) - midmag(1)) + fabs(getmag(idx[2]) - midmag(2)); split = !finite(err) || err > max*3*eps; // do the same for the curvature if (curved && !split) { double cerr = 0.0, cden = 0.0; // fixme for (i = 0; i < 3; i++) { cerr += fabs(phx[idx[i]] - midval[0][i]) + fabs(phy[idx[i]] - midval[1][i]); cden += fabs(phx[idx[i]]) + fabs(phy[idx[i]]); } split = (cerr > cden*2.5e-4); } // do extra tests at level 0, so as not to miss some functions with zero error at edge midpoints if (level == 0 && !split) { split = (fabs(getmag(8) - 0.5*(midmag(0) + midmag(1))) + fabs(getmag(9) - 0.5*(midmag(1) + midmag(2))) + fabs(getmag(4) - 0.5*(midmag(2) + midmag(0)))) > max*3*eps; } } // split the triangle if the error is too large, otherwise produce a linear triangle if (split) { if (curved) for (i = 0; i < 3; i++) { midval[0][i] = phx[idx[i]]; midval[1][i] = phy[idx[i]]; } // obtain mid-edge vertices int mid0 = get_vertex(iv0, iv1, midval[0][0], midval[1][0], getvalx(idx[0]), getvaly(idx[0])); int mid1 = get_vertex(iv1, iv2, midval[0][1], midval[1][1], getvalx(idx[1]), getvaly(idx[1])); int mid2 = get_vertex(iv2, iv0, midval[0][2], midval[1][2], getvalx(idx[2]), getvaly(idx[2])); // recur to sub-elements push_transform(0); process_triangle(iv0, mid0, mid2, level+1, xval, yval, phx, phy, tri_indices[1]); pop_transform(); push_transform(1); process_triangle(mid0, iv1, mid1, level+1, xval, yval, phx, phy, tri_indices[2]); pop_transform(); push_transform(2); process_triangle(mid2, mid1, iv2, level+1, xval, yval, phx, phy, tri_indices[3]); pop_transform(); push_transform(3); process_triangle(mid1, mid2, mid0, level+1, xval, yval, phx, phy, tri_indices[4]); pop_transform(); return; } } // no splitting: output a linear triangle add_triangle(iv0, iv1, iv2); }