void ElemCutter::cut_2D (const Elem & elem, const std::vector<Real> & vertex_distance_func) { #ifndef LIBMESH_HAVE_TRIANGLE // current implementation requires triangle! libMesh::err << "ERROR: current libMesh ElemCutter 2D implementation requires\n" << " the \"triangle\" library!\n" << std::endl; libmesh_not_implemented(); #else // OK, LIBMESH_HAVE_TRIANGLE std::cout << "Inside cut face element!\n"; libmesh_assert (_inside_mesh_2D.get() != nullptr); libmesh_assert (_outside_mesh_2D.get() != nullptr); _inside_mesh_2D->clear(); _outside_mesh_2D->clear(); for (unsigned int v=0; v<elem.n_vertices(); v++) { if (vertex_distance_func[v] >= 0.) _outside_mesh_2D->add_point (elem.point(v)); if (vertex_distance_func[v] <= 0.) _inside_mesh_2D->add_point (elem.point(v)); } for (const auto & pt : _intersection_pts) { _inside_mesh_2D->add_point(pt); _outside_mesh_2D->add_point(pt); } // Customize the variables for the triangulation // we will be cutting reference cell, and want as few triangles // as possible, so jack this up larger than the area we will be // triangulating so we are governed only by accurately defining // the boundaries. _triangle_inside->desired_area() = 100.; _triangle_outside->desired_area() = 100.; // allow for small angles _triangle_inside->minimum_angle() = 5.; _triangle_outside->minimum_angle() = 5.; // Turn off Laplacian mesh smoothing after generation. _triangle_inside->smooth_after_generating() = false; _triangle_outside->smooth_after_generating() = false; // Triangulate! _triangle_inside->triangulate(); _triangle_outside->triangulate(); // std::ostringstream name; // name << "cut_face_" // << cut_cntr++ // << ".dat"; // _inside_mesh_2D->write ("in_" + name.str()); // _outside_mesh_2D->write ("out_" + name.str()); // finally, add the elements to our lists. _inside_elem.clear(); _outside_elem.clear(); for (const auto & elem : _inside_mesh_2D->element_ptr_range()) _inside_elem.push_back (elem); for (const auto & elem : _outside_mesh_2D->element_ptr_range()) _outside_elem.push_back (elem); #endif }
void ElemCutter::cut_3D (const Elem & elem, const std::vector<Real> & vertex_distance_func) { #ifndef LIBMESH_HAVE_TETGEN // current implementation requires tetgen! libMesh::err << "ERROR: current libMesh ElemCutter 3D implementation requires\n" << " the \"tetgen\" library!\n" << std::endl; libmesh_not_implemented(); #else // OK, LIBMESH_HAVE_TETGEN std::cout << "Inside cut cell element!\n"; libmesh_assert (_inside_mesh_3D.get() != nullptr); libmesh_assert (_outside_mesh_3D.get() != nullptr); _inside_mesh_3D->clear(); _outside_mesh_3D->clear(); for (unsigned int v=0; v<elem.n_vertices(); v++) { if (vertex_distance_func[v] >= 0.) _outside_mesh_3D->add_point (elem.point(v)); if (vertex_distance_func[v] <= 0.) _inside_mesh_3D->add_point (elem.point(v)); } for (const auto & pt : _intersection_pts) { _inside_mesh_3D->add_point(pt); _outside_mesh_3D->add_point(pt); } // Triangulate! _tetgen_inside->triangulate_pointset(); //_inside_mesh_3D->print_info(); _tetgen_outside->triangulate_pointset(); //_outside_mesh_3D->print_info(); // (below generates some horribly expensive meshes, // but seems immune to the 0 volume problem). // _tetgen_inside->pointset_convexhull(); // _inside_mesh_3D->find_neighbors(); // _inside_mesh_3D->print_info(); // _tetgen_inside->triangulate_conformingDelaunayMesh (1.e3, 100.); // _inside_mesh_3D->print_info(); // _tetgen_outside->pointset_convexhull(); // _outside_mesh_3D->find_neighbors(); // _outside_mesh_3D->print_info(); // _tetgen_outside->triangulate_conformingDelaunayMesh (1.e3, 100.); // _outside_mesh_3D->print_info(); std::ostringstream name; name << "cut_cell_" << cut_cntr++ << ".dat"; _inside_mesh_3D->write ("in_" + name.str()); _outside_mesh_3D->write ("out_" + name.str()); // finally, add the elements to our lists. _inside_elem.clear(); _outside_elem.clear(); for (const auto & elem : _inside_mesh_3D->element_ptr_range()) if (elem->volume() > std::numeric_limits<Real>::epsilon()) _inside_elem.push_back (elem); for (const auto & elem : _outside_mesh_3D->element_ptr_range()) if (elem->volume() > std::numeric_limits<Real>::epsilon()) _outside_elem.push_back (elem); #endif }
// Begin the main program. int main (int argc, char ** argv) { // Initialize libMesh and any dependent libaries, like in example 2. LibMeshInit init (argc, argv); // Only our PETSc interface currently supports solves restricted to // subdomains libmesh_example_requires(libMesh::default_solver_package() == PETSC_SOLVERS, "--enable-petsc"); // Skip adaptive examples on a non-adaptive libMesh build #ifndef LIBMESH_ENABLE_AMR libmesh_example_requires(false, "--enable-amr"); #else // Declare a performance log for the main program // PerfLog perf_main("Main Program"); // Create a GetPot object to parse the command line GetPot command_line (argc, argv); // Check for proper calling arguments. if (argc < 3) { // This handy function will print the file name, line number, // specified message, and then throw an exception. libmesh_error_msg("Usage:\n" << "\t " << argv[0] << " -d 2(3)" << " -n 15"); } // Brief message to the user regarding the program name // and command line arguments. else { libMesh::out << "Running " << argv[0]; for (int i=1; i<argc; i++) libMesh::out << " " << argv[i]; libMesh::out << std::endl << std::endl; } // Read problem dimension from command line. Use int // instead of unsigned since the GetPot overload is ambiguous // otherwise. int dim = 2; if (command_line.search(1, "-d")) dim = command_line.next(dim); // Skip higher-dimensional examples on a lower-dimensional libMesh build libmesh_example_requires(dim <= LIBMESH_DIM, "2D/3D support"); // Create a mesh with user-defined dimension. // Read number of elements from command line int ps = 15; if (command_line.search(1, "-n")) ps = command_line.next(ps); // Read FE order from command line std::string order = "FIRST"; if (command_line.search(2, "-Order", "-o")) order = command_line.next(order); // Read FE Family from command line std::string family = "LAGRANGE"; if (command_line.search(2, "-FEFamily", "-f")) family = command_line.next(family); // Cannot use discontinuous basis. if ((family == "MONOMIAL") || (family == "XYZ")) libmesh_error_msg("This example requires a C^0 (or higher) FE basis."); // Create a mesh, with dimension to be overridden later, on the // default MPI communicator. Mesh mesh(init.comm()); // Use the MeshTools::Generation mesh generator to create a uniform // grid on the square [-1,1]^D. We instruct the mesh generator // to build a mesh of 8x8 Quad9 elements in 2D, or Hex27 // elements in 3D. Building these higher-order elements allows // us to use higher-order approximation, as in example 3. Real halfwidth = dim > 1 ? 1. : 0.; Real halfheight = dim > 2 ? 1. : 0.; if ((family == "LAGRANGE") && (order == "FIRST")) { // No reason to use high-order geometric elements if we are // solving with low-order finite elements. MeshTools::Generation::build_cube (mesh, ps, (dim>1) ? ps : 0, (dim>2) ? ps : 0, -1., 1., -halfwidth, halfwidth, -halfheight, halfheight, (dim==1) ? EDGE2 : ((dim == 2) ? QUAD4 : HEX8)); } else { MeshTools::Generation::build_cube (mesh, ps, (dim>1) ? ps : 0, (dim>2) ? ps : 0, -1., 1., -halfwidth, halfwidth, -halfheight, halfheight, (dim==1) ? EDGE3 : ((dim == 2) ? QUAD9 : HEX27)); } // To demonstate solving on a subdomain, we will solve only on the // interior of a circle (ball in 3d) with radius 0.8. So show that // this also works well on locally refined meshes, we refine once // all elements that are located on the boundary of this circle (or // ball). { // A MeshRefinement object is needed to refine meshes. MeshRefinement meshRefinement(mesh); // Loop over all elements. MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; if (elem->active()) { // Just check whether the current element has at least one // node inside and one node outside the circle. bool node_in = false; bool node_out = false; for (unsigned int i=0; i<elem->n_nodes(); i++) { double d = elem->point(i).norm(); if (d<0.8) { node_in = true; } else { node_out = true; } } if (node_in && node_out) { elem->set_refinement_flag(Elem::REFINE); } else { elem->set_refinement_flag(Elem::DO_NOTHING); } } else { elem->set_refinement_flag(Elem::INACTIVE); } } // Now actually refine. meshRefinement.refine_elements(); } // Print information about the mesh to the screen. mesh.print_info(); // Now set the subdomain_id of all elements whose centroid is inside // the circle to 1. { // Loop over all elements. MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem * elem = *elem_it; double d = elem->centroid().norm(); if (d<0.8) { elem->subdomain_id() = 1; } } } // Create an equation systems object. EquationSystems equation_systems (mesh); // Declare the system and its variables. // Create a system named "Poisson" LinearImplicitSystem & system = equation_systems.add_system<LinearImplicitSystem> ("Poisson"); // Add the variable "u" to "Poisson". "u" // will be approximated using second-order approximation. system.add_variable("u", Utility::string_to_enum<Order> (order), Utility::string_to_enum<FEFamily>(family)); // Give the system a pointer to the matrix assembly // function. system.attach_assemble_function (assemble_poisson); // Initialize the data structures for the equation system. equation_systems.init(); // Print information about the system to the screen. equation_systems.print_info(); mesh.print_info(); // Restrict solves to those elements that have subdomain_id set to 1. std::set<subdomain_id_type> id_list; id_list.insert(1); SystemSubsetBySubdomain::SubdomainSelectionByList selection(id_list); SystemSubsetBySubdomain subset(system, selection); system.restrict_solve_to(&subset, SUBSET_ZERO); // Note that using SUBSET_ZERO will cause all dofs outside the // subdomain to be cleared. This will, however, cause some hanging // nodes outside the subdomain to have inconsistent values. // Solve the system "Poisson", just like example 2. equation_systems.get_system("Poisson").solve(); // After solving the system write the solution // to a GMV-formatted plot file. if (dim == 1) { GnuPlotIO plot(mesh, "Subdomains Example 1, 1D", GnuPlotIO::GRID_ON); plot.write_equation_systems("gnuplot_script", equation_systems); } else { GMVIO (mesh).write_equation_systems ((dim == 3) ? "out_3.gmv" : "out_2.gmv", equation_systems); #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO (mesh).write_equation_systems ((dim == 3) ? "out_3.e" : "out_2.e", equation_systems); #endif // #ifdef LIBMESH_HAVE_EXODUS_API } #endif // #ifndef LIBMESH_ENABLE_AMR // All done. return 0; }
void MeshTools::Subdivision::add_boundary_ghosts(MeshBase & mesh) { static const Real tol = 1e-5; // add the mirrored ghost elements (without using iterators, because the mesh is modified in the course) std::vector<Tri3Subdivision *> ghost_elems; std::vector<Node *> ghost_nodes; const unsigned int n_elem = mesh.n_elem(); for (unsigned int eid = 0; eid < n_elem; ++eid) { Elem * elem = mesh.elem(eid); libmesh_assert_equal_to(elem->type(), TRI3SUBDIVISION); // If the triangle happens to be in a corner (two boundary // edges), we perform a counter-clockwise loop by mirroring the // previous triangle until we come back to the original // triangle. This prevents degenerated triangles in the mesh // corners and guarantees that the node in the middle of the // loop is of valence=6. for (unsigned int i = 0; i < elem->n_sides(); ++i) { libmesh_assert_not_equal_to(elem->neighbor(i), elem); if (elem->neighbor(i) == libmesh_nullptr && elem->neighbor(next[i]) == libmesh_nullptr) { Elem * nelem = elem; unsigned int k = i; for (unsigned int l=0;l<4;l++) { // this is the vertex to be mirrored Point point = nelem->point(k) + nelem->point(next[k]) - nelem->point(prev[k]); // Check if the proposed vertex doesn't coincide // with one of the existing vertices. This is // necessary because for some triangulations, it can // happen that two mirrored ghost vertices coincide, // which would then lead to a zero size ghost // element below. Node * node = libmesh_nullptr; for (unsigned int j = 0; j < ghost_nodes.size(); ++j) { if ((*ghost_nodes[j] - point).size() < tol * (elem->point(k) - point).size()) { node = ghost_nodes[j]; break; } } // add the new vertex only if no other is nearby if (node == libmesh_nullptr) { node = mesh.add_point(point); ghost_nodes.push_back(node); } Tri3Subdivision * newelem = new Tri3Subdivision(); // add the first new ghost element to the list just as in the non-corner case if (l == 0) ghost_elems.push_back(newelem); newelem->set_node(0) = nelem->get_node(next[k]); newelem->set_node(1) = nelem->get_node(k); newelem->set_node(2) = node; newelem->set_neighbor(0, nelem); newelem->set_ghost(true); if (l>0) newelem->set_neighbor(2, libmesh_nullptr); nelem->set_neighbor(k, newelem); mesh.add_elem(newelem); mesh.get_boundary_info().add_node(nelem->get_node(k), 1); mesh.get_boundary_info().add_node(nelem->get_node(next[k]), 1); mesh.get_boundary_info().add_node(nelem->get_node(prev[k]), 1); mesh.get_boundary_info().add_node(node, 1); nelem = newelem; k = 2 ; } Tri3Subdivision * newelem = new Tri3Subdivision(); newelem->set_node(0) = elem->get_node(next[i]); newelem->set_node(1) = nelem->get_node(2); newelem->set_node(2) = elem->get_node(prev[i]); newelem->set_neighbor(0, nelem); nelem->set_neighbor(2, newelem); newelem->set_ghost(true); newelem->set_neighbor(2, elem); elem->set_neighbor(next[i],newelem); mesh.add_elem(newelem); break; } } for (unsigned int i = 0; i < elem->n_sides(); ++i) { libmesh_assert_not_equal_to(elem->neighbor(i), elem); if (elem->neighbor(i) == libmesh_nullptr) { // this is the vertex to be mirrored Point point = elem->point(i) + elem->point(next[i]) - elem->point(prev[i]); // Check if the proposed vertex doesn't coincide with // one of the existing vertices. This is necessary // because for some triangulations, it can happen that // two mirrored ghost vertices coincide, which would // then lead to a zero size ghost element below. Node * node = libmesh_nullptr; for (unsigned int j = 0; j < ghost_nodes.size(); ++j) { if ((*ghost_nodes[j] - point).size() < tol * (elem->point(i) - point).size()) { node = ghost_nodes[j]; break; } } // add the new vertex only if no other is nearby if (node == libmesh_nullptr) { node = mesh.add_point(point); ghost_nodes.push_back(node); } Tri3Subdivision * newelem = new Tri3Subdivision(); ghost_elems.push_back(newelem); newelem->set_node(0) = elem->get_node(next[i]); newelem->set_node(1) = elem->get_node(i); newelem->set_node(2) = node; newelem->set_neighbor(0, elem); newelem->set_ghost(true); elem->set_neighbor(i, newelem); mesh.add_elem(newelem); mesh.get_boundary_info().add_node(elem->get_node(i), 1); mesh.get_boundary_info().add_node(elem->get_node(next[i]), 1); mesh.get_boundary_info().add_node(elem->get_node(prev[i]), 1); mesh.get_boundary_info().add_node(node, 1); } } } // add the missing ghost elements (connecting new ghost nodes) std::vector<Tri3Subdivision *> missing_ghost_elems; std::vector<Tri3Subdivision *>::iterator ghost_el = ghost_elems.begin(); const std::vector<Tri3Subdivision *>::iterator end_ghost_el = ghost_elems.end(); for (; ghost_el != end_ghost_el; ++ghost_el) { Tri3Subdivision * elem = *ghost_el; libmesh_assert(elem->is_ghost()); for (unsigned int i = 0; i < elem->n_sides(); ++i) { if (elem->neighbor(i) == libmesh_nullptr && elem->neighbor(prev[i]) != libmesh_nullptr) { // go around counter-clockwise Tri3Subdivision * nb1 = static_cast<Tri3Subdivision *>(elem->neighbor(prev[i])); Tri3Subdivision * nb2 = nb1; unsigned int j = i; unsigned int n_nb = 0; while (nb1 != libmesh_nullptr && nb1->id() != elem->id()) { j = nb1->local_node_number(elem->node(i)); nb2 = nb1; nb1 = static_cast<Tri3Subdivision *>(nb1->neighbor(prev[j])); libmesh_assert(nb1 == libmesh_nullptr || nb1->id() != nb2->id()); n_nb++; } libmesh_assert_not_equal_to(nb2->id(), elem->id()); // Above, we merged coinciding ghost vertices. Therefore, we need // to exclude the case where there is no ghost element to add between // these two (identical) ghost nodes. if (elem->get_node(next[i])->id() == nb2->get_node(prev[j])->id()) break; // If the number of already present neighbors is less than 4, we add another extra element // so that the node in the middle of the loop ends up being of valence=6. // This case usually happens when the middle node corresponds to a corner of the original mesh, // and the extra element below prevents degenerated triangles in the mesh corners. if (n_nb < 4) { // this is the vertex to be mirrored Point point = nb2->point(j) + nb2->point(prev[j]) - nb2->point(next[j]); // Check if the proposed vertex doesn't coincide with one of the existing vertices. // This is necessary because for some triangulations, it can happen that two mirrored // ghost vertices coincide, which would then lead to a zero size ghost element below. Node * node = libmesh_nullptr; for (unsigned int k = 0; k < ghost_nodes.size(); ++k) { if ((*ghost_nodes[k] - point).size() < tol * (nb2->point(j) - point).size()) { node = ghost_nodes[k]; break; } } // add the new vertex only if no other is nearby if (node == libmesh_nullptr) { node = mesh.add_point(point); ghost_nodes.push_back(node); } Tri3Subdivision * newelem = new Tri3Subdivision(); newelem->set_node(0) = nb2->get_node(j); newelem->set_node(1) = nb2->get_node(prev[j]); newelem->set_node(2) = node; newelem->set_neighbor(0, nb2); newelem->set_neighbor(1, libmesh_nullptr); newelem->set_ghost(true); nb2->set_neighbor(prev[j], newelem); mesh.add_elem(newelem); mesh.get_boundary_info().add_node(nb2->get_node(j), 1); mesh.get_boundary_info().add_node(nb2->get_node(prev[j]), 1); mesh.get_boundary_info().add_node(node, 1); nb2 = newelem; j = nb2->local_node_number(elem->node(i)); } Tri3Subdivision * newelem = new Tri3Subdivision(); newelem->set_node(0) = elem->get_node(next[i]); newelem->set_node(1) = elem->get_node(i); newelem->set_node(2) = nb2->get_node(prev[j]); newelem->set_neighbor(0, elem); newelem->set_neighbor(1, nb2); newelem->set_neighbor(2, libmesh_nullptr); newelem->set_ghost(true); elem->set_neighbor(i, newelem); nb2->set_neighbor(prev[j], newelem); missing_ghost_elems.push_back(newelem); break; } } // end side loop } // end ghost element loop // add the missing ghost elements to the mesh std::vector<Tri3Subdivision *>::iterator missing_el = missing_ghost_elems.begin(); const std::vector<Tri3Subdivision *>::iterator end_missing_el = missing_ghost_elems.end(); for (; missing_el != end_missing_el; ++missing_el) mesh.add_elem(*missing_el); }
void UnstructuredMesh::find_neighbors (const bool reset_remote_elements, const bool reset_current_list) { // We might actually want to run this on an empty mesh // (e.g. the boundary mesh for a nonexistant bcid!) // libmesh_assert_not_equal_to (this->n_nodes(), 0); // libmesh_assert_not_equal_to (this->n_elem(), 0); // This function must be run on all processors at once parallel_object_only(); LOG_SCOPE("find_neighbors()", "Mesh"); const element_iterator el_end = this->elements_end(); //TODO:[BSK] This should be removed later?! if (reset_current_list) for (element_iterator el = this->elements_begin(); el != el_end; ++el) { Elem * e = *el; for (unsigned int s=0; s<e->n_neighbors(); s++) if (e->neighbor_ptr(s) != remote_elem || reset_remote_elements) e->set_neighbor(s, libmesh_nullptr); } // Find neighboring elements by first finding elements // with identical side keys and then check to see if they // are neighbors { // data structures -- Use the hash_multimap if available typedef unsigned int key_type; typedef std::pair<Elem *, unsigned char> val_type; typedef std::pair<key_type, val_type> key_val_pair; typedef LIBMESH_BEST_UNORDERED_MULTIMAP<key_type, val_type> map_type; // A map from side keys to corresponding elements & side numbers map_type side_to_elem_map; for (element_iterator el = this->elements_begin(); el != el_end; ++el) { Elem * element = *el; for (unsigned char ms=0; ms<element->n_neighbors(); ms++) { next_side: // If we haven't yet found a neighbor on this side, try. // Even if we think our neighbor is remote, that // information may be out of date. if (element->neighbor_ptr(ms) == libmesh_nullptr || element->neighbor_ptr(ms) == remote_elem) { // Get the key for the side of this element const unsigned int key = element->key(ms); // Look for elements that have an identical side key std::pair <map_type::iterator, map_type::iterator> bounds = side_to_elem_map.equal_range(key); // May be multiple keys, check all the possible // elements which _might_ be neighbors. if (bounds.first != bounds.second) { // Get the side for this element const UniquePtr<Elem> my_side(element->side_ptr(ms)); // Look at all the entries with an equivalent key while (bounds.first != bounds.second) { // Get the potential element Elem * neighbor = bounds.first->second.first; // Get the side for the neighboring element const unsigned int ns = bounds.first->second.second; const UniquePtr<Elem> their_side(neighbor->side_ptr(ns)); //libmesh_assert(my_side.get()); //libmesh_assert(their_side.get()); // If found a match with my side // // We need special tests here for 1D: // since parents and children have an equal // side (i.e. a node), we need to check // ns != ms, and we also check level() to // avoid setting our neighbor pointer to // any of our neighbor's descendants if( (*my_side == *their_side) && (element->level() == neighbor->level()) && ((element->dim() != 1) || (ns != ms)) ) { // So share a side. Is this a mixed pair // of subactive and active/ancestor // elements? // If not, then we're neighbors. // If so, then the subactive's neighbor is if (element->subactive() == neighbor->subactive()) { // an element is only subactive if it has // been coarsened but not deleted element->set_neighbor (ms,neighbor); neighbor->set_neighbor(ns,element); } else if (element->subactive()) { element->set_neighbor(ms,neighbor); } else if (neighbor->subactive()) { neighbor->set_neighbor(ns,element); } side_to_elem_map.erase (bounds.first); // get out of this nested crap goto next_side; } ++bounds.first; } } // didn't find a match... // Build the map entry for this element key_val_pair kvp; kvp.first = key; kvp.second.first = element; kvp.second.second = ms; // use the lower bound as a hint for // where to put it. #if defined(LIBMESH_HAVE_UNORDERED_MAP) || defined(LIBMESH_HAVE_TR1_UNORDERED_MAP) || defined(LIBMESH_HAVE_HASH_MAP) || defined(LIBMESH_HAVE_EXT_HASH_MAP) side_to_elem_map.insert (kvp); #else side_to_elem_map.insert (bounds.first,kvp); #endif } } } } #ifdef LIBMESH_ENABLE_AMR /** * Here we look at all of the child elements which * don't already have valid neighbors. * * If a child element has a NULL neighbor it is * either because it is on the boundary or because * its neighbor is at a different level. In the * latter case we must get the neighbor from the * parent. * * If a child element has a remote_elem neighbor * on a boundary it shares with its parent, that * info may have become out-dated through coarsening * of the neighbor's parent. In this case, if the * parent's neighbor is active then the child should * share it. * * Furthermore, that neighbor better be active, * otherwise we missed a child somewhere. * * * We also need to look through children ordered by increasing * refinement level in order to add new interior_parent() links in * boundary elements which have just been generated by refinement, * and fix links in boundary elements whose previous * interior_parent() has just been coarsened away. */ const unsigned int n_levels = MeshTools::n_levels(*this); for (unsigned int level = 1; level < n_levels; ++level) { element_iterator end = this->level_elements_end(level); for (element_iterator el = this->level_elements_begin(level); el != end; ++el) { Elem * current_elem = *el; libmesh_assert(current_elem); Elem * parent = current_elem->parent(); libmesh_assert(parent); const unsigned int my_child_num = parent->which_child_am_i(current_elem); for (unsigned int s=0; s < current_elem->n_neighbors(); s++) { if (current_elem->neighbor_ptr(s) == libmesh_nullptr || (current_elem->neighbor_ptr(s) == remote_elem && parent->is_child_on_side(my_child_num, s))) { Elem * neigh = parent->neighbor_ptr(s); // If neigh was refined and had non-subactive children // made remote earlier, then a non-subactive elem should // actually have one of those remote children as a // neighbor if (neigh && (neigh->ancestor()) && (!current_elem->subactive())) { #ifdef DEBUG // Let's make sure that "had children made remote" // situation is actually the case libmesh_assert(neigh->has_children()); bool neigh_has_remote_children = false; for (unsigned int c = 0; c != neigh->n_children(); ++c) { if (neigh->child_ptr(c) == remote_elem) neigh_has_remote_children = true; } libmesh_assert(neigh_has_remote_children); // And let's double-check that we don't have // a remote_elem neighboring a local element libmesh_assert_not_equal_to (current_elem->processor_id(), this->processor_id()); #endif // DEBUG neigh = const_cast<RemoteElem *>(remote_elem); } if (!current_elem->subactive()) current_elem->set_neighbor(s, neigh); #ifdef DEBUG if (neigh != libmesh_nullptr && neigh != remote_elem) // We ignore subactive elements here because // we don't care about neighbors of subactive element. if ((!neigh->active()) && (!current_elem->subactive())) { libMesh::err << "On processor " << this->processor_id() << std::endl; libMesh::err << "Bad element ID = " << current_elem->id() << ", Side " << s << ", Bad neighbor ID = " << neigh->id() << std::endl; libMesh::err << "Bad element proc_ID = " << current_elem->processor_id() << ", Bad neighbor proc_ID = " << neigh->processor_id() << std::endl; libMesh::err << "Bad element size = " << current_elem->hmin() << ", Bad neighbor size = " << neigh->hmin() << std::endl; libMesh::err << "Bad element center = " << current_elem->centroid() << ", Bad neighbor center = " << neigh->centroid() << std::endl; libMesh::err << "ERROR: " << (current_elem->active()?"Active":"Ancestor") << " Element at level " << current_elem->level() << std::endl; libMesh::err << "with " << (parent->active()?"active": (parent->subactive()?"subactive":"ancestor")) << " parent share " << (neigh->subactive()?"subactive":"ancestor") << " neighbor at level " << neigh->level() << std::endl; NameBasedIO(*this).write ("bad_mesh.gmv"); libmesh_error_msg("Problematic mesh written to bad_mesh.gmv."); } #endif // DEBUG } } // We can skip to the next element if we're full-dimension // and therefore don't have any interior parents if (current_elem->dim() >= LIBMESH_DIM) continue; // We have no interior parents unless we can find one later current_elem->set_interior_parent(libmesh_nullptr); Elem * pip = parent->interior_parent(); if (!pip) continue; // If there's no interior_parent children, whether due to a // remote element or a non-conformity, then there's no // children to search. if (pip == remote_elem || pip->active()) { current_elem->set_interior_parent(pip); continue; } // For node comparisons we'll need a sensible tolerance Real node_tolerance = current_elem->hmin() * TOLERANCE; // Otherwise our interior_parent should be a child of our // parent's interior_parent. for (unsigned int c=0; c != pip->n_children(); ++c) { Elem * child = pip->child_ptr(c); // If we have a remote_elem, that might be our // interior_parent. We'll set it provisionally now and // keep trying to find something better. if (child == remote_elem) { current_elem->set_interior_parent (const_cast<RemoteElem *>(remote_elem)); continue; } bool child_contains_our_nodes = true; for (unsigned int n=0; n != current_elem->n_nodes(); ++n) { bool child_contains_this_node = false; for (unsigned int cn=0; cn != child->n_nodes(); ++cn) if (child->point(cn).absolute_fuzzy_equals (current_elem->point(n), node_tolerance)) { child_contains_this_node = true; break; } if (!child_contains_this_node) { child_contains_our_nodes = false; break; } } if (child_contains_our_nodes) { current_elem->set_interior_parent(child); break; } } // We should have found *some* interior_parent at this // point, whether semilocal or remote. libmesh_assert(current_elem->interior_parent()); } } #endif // AMR #ifdef DEBUG MeshTools::libmesh_assert_valid_neighbors(*this, !reset_remote_elements); MeshTools::libmesh_assert_valid_amr_interior_parents(*this); #endif }
int main(int argc, char** argv){ // Initilize libMesh LibMeshInit init (argc, argv); // Create the mesh, single element Mesh mesh; MeshTools::Generation::build_square(mesh, 1, 1, -1, 1, -1, 1, QUAD4); // Create an equation system EquationSystems eq_sys(mesh); // Create the equation systems via shared_ptr pointers boost::shared_ptr<ThermoEq> thermo(new ThermoEq(eq_sys)); boost::shared_ptr<MomentumEq> momentum(new MomentumEq(eq_sys, FIRST)); boost::shared_ptr<ConcentrationEq> concentration(new ConcentrationEq(eq_sys, FIRST)); boost::shared_ptr<EnergyEq> energy(new EnergyEq(eq_sys, FIRST)); // Link the initialization functions momentum->add_initial_function(initial_velocity); concentration->add_initial_function(initial_concentration); energy->add_initial_function(initial_temperature); // Add the necessary cross-linking between the systems via their pointers thermo->momentum = momentum; thermo->energy = energy; thermo->concentration = concentration; energy->thermo = thermo; energy->momentum = momentum; // Initialize the various systems momentum->init(); concentration->init(); energy->init(); thermo->init(); // Get a pointer to the first (and only) element Elem* elem = mesh.elem(0); // Display the values for initial enthalpy; computed from temp. printf("\n\nTEMP. TO ENTHALPY CONVERSION:\n"); for (unsigned int i = 0; i < elem->n_nodes(); i++){ Point& p = elem->point(i); Number h = energy->point_value(0,p); printf("\th = %g (%g, %g)\n", h, p(0), p(1)); } // thermo->test(elem); // DenseVector<Number> output(1); //energy.enthalpy(output, p, 0.0); //energy.init(); // Thermodynamics links //data.init(); //printf("initilized = %s\n", (data.velocity_ptr->initialized())?"true":"false"); /* // Print some basic element information printf("\n\nELEMENT INFORMATION:\n"); // Test that values are correct, use first (only) element VectorValue<Number> v; Elem* elem = mesh.elem(0); for (unsigned int i = 0; i < elem->n_nodes(); i++){ Point& p = elem->point(i); v = data.velocity_ptr->point_value(p); printf("\tPoint %g, %g\tv = %g, %g\n", p(0),p(1),v(0),v(1)); } // Test the element length printf("\nTESTING: element data\n"); Number h = data.element_length(elem); printf("\tElement length (%f): %f\n", 1.065004, h); // Test the tau_1 value printf("\nTESTING: Tau_1\n"); printf("\tTau_1: %g\n", data.tau_1(elem->point(0), data.element_length(elem))); printf("\tTau_1: %g\n", data.tau_1(elem->point(1), data.element_length(elem))); printf("\tTau_1: %g\n", data.tau_1(elem->point(2), data.element_length(elem))); printf("\tTau_1: %g\n", data.tau_1(elem->point(3), data.element_length(elem))); */ // Test the EnergyEq assembly printf("\nTESTING: energy eq. assembly\n"); energy->assemble(); }
void Elem::coarsen() { libmesh_assert_equal_to (this->refinement_flag(), Elem::COARSEN_INACTIVE); libmesh_assert (!this->active()); // We no longer delete children until MeshRefinement::contract() // delete [] _children; // _children = nullptr; unsigned int parent_p_level = 0; // re-compute hanging node nodal locations for (unsigned int c = 0, nc = this->n_children(); c != nc; ++c) { Elem * mychild = this->child_ptr(c); if (mychild == remote_elem) continue; for (unsigned int cnode=0; cnode != mychild->n_nodes(); ++cnode) { Point new_pos; bool calculated_new_pos = false; for (unsigned int n=0; n<this->n_nodes(); n++) { // The value from the embedding matrix const float em_val = this->embedding_matrix(c,cnode,n); // The node location is somewhere between existing vertices if ((em_val != 0.) && (em_val != 1.)) { new_pos.add_scaled (this->point(n), em_val); calculated_new_pos = true; } } if (calculated_new_pos) { //Move the existing node back into it's original location for (unsigned int i=0; i<LIBMESH_DIM; i++) { Point & child_node = mychild->point(cnode); child_node(i)=new_pos(i); } } } } for (auto & mychild : this->child_ref_range()) { if (&mychild == remote_elem) continue; libmesh_assert_equal_to (mychild.refinement_flag(), Elem::COARSEN); mychild.set_refinement_flag(Elem::INACTIVE); if (mychild.p_level() > parent_p_level) parent_p_level = mychild.p_level(); } this->set_refinement_flag(Elem::JUST_COARSENED); this->set_p_level(parent_p_level); libmesh_assert (this->active()); }