//----------------------------------------------------------------------------- void dolfin::p_refine(Mesh& refined_mesh, const Mesh& mesh) { MeshEditor editor; if (mesh.geometry().degree() != 1) { dolfin_error("refine.cpp", "increase polynomial degree of mesh", "Currently only linear -> quadratic is supported"); } const CellType::Type cell_type = mesh.type().cell_type(); if (cell_type != CellType::Type::triangle and cell_type != CellType::Type::tetrahedron and cell_type != CellType::Type::interval) { dolfin_error("refine.cpp", "increase polynomial degree of mesh", "Unsupported cell type"); } const std::size_t tdim = mesh.topology().dim(); const std::size_t gdim = mesh.geometry().dim(); editor.open(refined_mesh, cell_type, tdim, gdim, 2); // Copy over mesh editor.init_vertices_global(mesh.num_entities(0), mesh.num_entities_global(0)); for (VertexIterator v(mesh); !v.end(); ++v) editor.add_vertex(v->index(), v->point()); editor.init_cells_global(mesh.num_entities(tdim), mesh.num_entities_global(tdim)); std::vector<std::size_t> verts(tdim + 1); for (CellIterator c(mesh); !c.end(); ++c) { std::copy(c->entities(0), c->entities(0) + tdim + 1, verts.begin()); editor.add_cell(c->index(), verts); } // Initialise edges editor.init_entities(); // Add points at centres of edges for (EdgeIterator e(refined_mesh); !e.end(); ++e) editor.add_entity_point(1, 0, e->index(), e->midpoint()); editor.close(); }
//----------------------------------------------------------------------------- UnitTriangleMesh::UnitTriangleMesh() : Mesh() { // Receive mesh according to parallel policy if (MPI::is_receiver(this->mpi_comm())) { MeshPartitioning::build_distributed_mesh(*this); return; } // Open mesh for editing MeshEditor editor; editor.open(*this, CellType::triangle, 2, 2); // Create vertices editor.init_vertices_global(3, 3); std::vector<double> x(2); x[0] = 0.0; x[1] = 0.0; editor.add_vertex(0, x); x[0] = 1.0; x[1] = 0.0; editor.add_vertex(1, x); x[0] = 0.0; x[1] = 1.0; editor.add_vertex(2, x); // Create cells editor.init_cells_global(1, 1); std::vector<std::size_t> cell_data(3); cell_data[0] = 0; cell_data[1] = 1; cell_data[2] = 2; editor.add_cell(0, cell_data); // Close mesh editor editor.close(); // Broadcast mesh according to parallel policy if (MPI::is_broadcaster(this->mpi_comm())) { MeshPartitioning::build_distributed_mesh(*this); return; } }
//----------------------------------------------------------------------------- void BoundaryComputation::compute_boundary(const Mesh& mesh, const std::string type, BoundaryMesh& boundary) { // We iterate over all facets in the mesh and check if they are on // the boundary. A facet is on the boundary if it is connected to // exactly one cell. log(TRACE, "Computing boundary mesh."); bool exterior = true; bool interior = true; if (type == "exterior") interior = false; else if (type == "interior") exterior = false; else if (type != "local") { dolfin_error("BoundaryComputation.cpp", "determine boundary mesh type", "Unknown boundary type (%d)", type.c_str()); } // Get my MPI process rank and number of MPI processes const std::size_t my_rank = MPI::rank(mesh.mpi_comm()); const std::size_t num_processes = MPI::size(mesh.mpi_comm()); // Open boundary mesh for editing const std::size_t D = mesh.topology().dim(); MeshEditor editor; editor.open(boundary, mesh.type().facet_type(), D - 1, mesh.geometry().dim()); // Generate facet - cell connectivity if not generated mesh.init(D - 1, D); // Temporary arrays for assignment of indices to vertices on the boundary std::map<std::size_t, std::size_t> boundary_vertices; // Map of index "owners" (process responsible for assigning global index) std::map< std::size_t, std::size_t > global_index_owner; // Shared vertices for full mesh // FIXME: const_cast const std::map<unsigned int, std::set<unsigned int>> & shared_vertices = const_cast<Mesh&>(mesh).topology().shared_entities(0); // Shared vertices for boundary mesh std::map<unsigned int, std::set<unsigned int>> shared_boundary_vertices; if (exterior) { // Extract shared vertices if vertex is identified as part of globally // exterior facet. std::vector<std::size_t> boundary_global_indices; for (std::map<unsigned int, std::set<unsigned int>>::const_iterator sv_it=shared_vertices.begin(); sv_it != shared_vertices.end(); ++sv_it) { std::size_t local_mesh_index = sv_it->first; Vertex v(mesh, local_mesh_index); for (FacetIterator f(v); !f.end(); ++f) { if (f->num_global_entities(D) == 1) { const std::size_t global_mesh_index = mesh.topology().global_indices(0)[local_mesh_index]; shared_boundary_vertices[local_mesh_index] = sv_it->second; boundary_global_indices.push_back(global_mesh_index); break; } } } // Distribute all shared boundary vertices std::vector<std::vector<std::size_t>> boundary_global_indices_all; MPI::all_gather(mesh.mpi_comm(), boundary_global_indices, boundary_global_indices_all); // Identify and clean up discrepancies between shared vertices of full mesh // and shared vertices of boundary mesh for (auto sbv_it = shared_boundary_vertices.begin(); sbv_it != shared_boundary_vertices.end(); ) { std::size_t local_mesh_index = sbv_it->first; const std::size_t global_mesh_index = mesh.topology().global_indices(0)[local_mesh_index]; // Check if this vertex is identified as boundary vertex on // other processes sharing this vertex std::set<unsigned int> &other_processes = sbv_it->second; for (auto op_it=other_processes.begin(); op_it != other_processes.end(); ) { // Check if vertex is identified as boundary vertex on process *op_it bool is_boundary_vertex = (std::find(boundary_global_indices_all[*op_it].begin(), boundary_global_indices_all[*op_it].end(), global_mesh_index) != boundary_global_indices_all[*op_it].end()); // Erase item if this is not identified as a boundary vertex // on process *op_it, and increment iterator if (!is_boundary_vertex) { // Erase item while carefully avoiding invalidating the // iterator: First increment it to get the next, valid // iterator, and then erase what it pointed to from // other_processes other_processes.erase(op_it++); } else ++op_it; } // Erase item from map if no other processes identify this // vertex as a boundary vertex, and increment iterator if (other_processes.size() == 0) { // Erase carefully as above shared_boundary_vertices.erase(sbv_it++); } else ++sbv_it; } } else { // If interior boundary, shared vertices are the same shared_boundary_vertices = shared_vertices; } // Determine boundary facet, count boundary vertices and facets, and // assign vertex indices std::size_t num_boundary_vertices = 0; std::size_t num_owned_vertices = 0; std::size_t num_boundary_cells = 0; MeshFunction<bool> boundary_facet(reference_to_no_delete_pointer(mesh), D - 1, false); for (FacetIterator f(mesh); !f.end(); ++f) { // Boundary facets are connected to exactly one cell if (f->num_entities(D) == 1) { const bool global_exterior_facet = (f->num_global_entities(D) == 1); if (global_exterior_facet && exterior) boundary_facet[*f] = true; else if (!global_exterior_facet && interior) boundary_facet[*f] = true; if (boundary_facet[*f]) { // Count boundary vertices and assign indices for (VertexIterator v(*f); !v.end(); ++v) { const std::size_t local_mesh_index = v->index(); if (boundary_vertices.find(local_mesh_index) == boundary_vertices.end()) { const std::size_t local_boundary_index = num_boundary_vertices; boundary_vertices[local_mesh_index] = local_boundary_index; // Determine "owner" of global_mesh_index std::size_t owner = my_rank; std::map<unsigned int, std::set<unsigned int>>::const_iterator other_processes_it = shared_boundary_vertices.find(local_mesh_index); if (other_processes_it != shared_boundary_vertices.end() && D > 1) { const std::set<unsigned int>& other_processes = other_processes_it->second; const std::size_t min_process = *std::min_element(other_processes.begin(), other_processes.end()); boundary.topology().shared_entities(0)[local_boundary_index] = other_processes; // FIXME: More sophisticated ownership determination if (min_process < owner) owner = min_process; } const std::size_t global_mesh_index = mesh.topology().global_indices(0)[local_mesh_index]; global_index_owner[global_mesh_index] = owner; // Update counts if (owner == my_rank) num_owned_vertices++; num_boundary_vertices++; } } // Count boundary cells (facets of the mesh) num_boundary_cells++; } } } // Initiate boundary topology /* boundary.topology().init(0, num_boundary_vertices, MPI::sum(mesh.mpi_comm(), num_owned_vertices)); boundary.topology().init(D - 1, num_boundary_cells, MPI::sum(mesh.mpi_comm(), num_boundary_cells)); */ // Specify number of vertices and cells editor.init_vertices_global(num_boundary_vertices, MPI::sum(mesh.mpi_comm(), num_owned_vertices)); editor.init_cells_global(num_boundary_cells, MPI::sum(mesh.mpi_comm(), num_boundary_cells)); // Write vertex map MeshFunction<std::size_t>& vertex_map = boundary.entity_map(0); if (num_boundary_vertices > 0) { vertex_map.init(reference_to_no_delete_pointer(boundary), 0, num_boundary_vertices); } std::map<std::size_t, std::size_t>::const_iterator it; for (it = boundary_vertices.begin(); it != boundary_vertices.end(); ++it) vertex_map[it->second] = it->first; // Get vertex ownership distribution, and find index to start global // numbering from std::vector<std::size_t> ownership_distribution(num_processes); MPI::all_gather(mesh.mpi_comm(), num_owned_vertices, ownership_distribution); std::size_t start_index = 0; for (std::size_t j = 0; j < my_rank; j++) start_index += ownership_distribution[j]; // Set global indices of owned vertices, request global indices for // vertices owned elsewhere std::map<std::size_t, std::size_t> global_indices; std::vector<std::vector<std::size_t>> request_global_indices(num_processes); std::size_t current_index = start_index; for (std::size_t local_boundary_index = 0; local_boundary_index<num_boundary_vertices; local_boundary_index++) { const std::size_t local_mesh_index = vertex_map[local_boundary_index]; const std::size_t global_mesh_index = mesh.topology().global_indices(0)[local_mesh_index]; const std::size_t owner = global_index_owner[global_mesh_index]; if (owner != my_rank) request_global_indices[owner].push_back(global_mesh_index); else global_indices[global_mesh_index] = current_index++; } // Send and receive requests from other processes std::vector<std::vector<std::size_t>> global_index_requests(num_processes); MPI::all_to_all(mesh.mpi_comm(), request_global_indices, global_index_requests); // Find response to requests of global indices std::vector<std::vector<std::size_t>> respond_global_indices(num_processes); for (std::size_t i = 0; i < num_processes; i++) { const std::size_t N = global_index_requests[i].size(); respond_global_indices[i].resize(N); for (std::size_t j = 0; j < N; j++) respond_global_indices[i][j] = global_indices[global_index_requests[i][j]]; } // Scatter responses back to requesting processes std::vector<std::vector<std::size_t>> global_index_responses(num_processes); MPI::all_to_all(mesh.mpi_comm(), respond_global_indices, global_index_responses); // Update global_indices for (std::size_t i = 0; i < num_processes; i++) { const std::size_t N = global_index_responses[i].size(); // Check that responses are the same size as the requests made dolfin_assert(global_index_responses[i].size() == request_global_indices[i].size()); for (std::size_t j = 0; j < N; j++) { const std::size_t global_mesh_index = request_global_indices[i][j]; const std::size_t global_boundary_index = global_index_responses[i][j]; global_indices[global_mesh_index] = global_boundary_index; } } // Create vertices for (std::size_t local_boundary_index = 0; local_boundary_index < num_boundary_vertices; local_boundary_index++) { const std::size_t local_mesh_index = vertex_map[local_boundary_index]; const std::size_t global_mesh_index = mesh.topology().global_indices(0)[local_mesh_index]; const std::size_t global_boundary_index = global_indices[global_mesh_index]; Vertex v(mesh, local_mesh_index); editor.add_vertex_global(local_boundary_index, global_boundary_index, v.point()); } // Find global index to start cell numbering from for current process std::vector<std::size_t> cell_distribution(num_processes); MPI::all_gather(mesh.mpi_comm(), num_boundary_cells, cell_distribution); std::size_t start_cell_index = 0; for (std::size_t i = 0; i < my_rank; i++) start_cell_index += cell_distribution[i]; // Create cells (facets) and map between boundary mesh cells and facets parent MeshFunction<std::size_t>& cell_map = boundary.entity_map(D - 1); if (num_boundary_cells > 0) { cell_map.init(reference_to_no_delete_pointer(boundary), D - 1, num_boundary_cells); } std::vector<std::size_t> cell(boundary.type().num_vertices(boundary.topology().dim())); std::size_t current_cell = 0; for (FacetIterator f(mesh); !f.end(); ++f) { if (boundary_facet[*f]) { // Compute new vertex numbers for cell const unsigned int* vertices = f->entities(0); for (std::size_t i = 0; i < cell.size(); i++) cell[i] = boundary_vertices[vertices[i]]; // Reorder vertices so facet is right-oriented w.r.t. facet // normal reorder(cell, *f); // Create mapping from boundary cell to mesh facet if requested if (!cell_map.empty()) cell_map[current_cell] = f->index(); // Add cell editor.add_cell(current_cell, start_cell_index+current_cell, cell); current_cell++; } } // Close mesh editor. Note the argument order=false to prevent // ordering from destroying the orientation of facets accomplished // by calling reorder() below. editor.close(false); }
//----------------------------------------------------------------------------- bool LocalMeshCoarsening::coarsen_cell(Mesh& mesh, Mesh& coarse_mesh, int cellid, std::vector<int>& old2new_vertex, std::vector<int>& old2new_cell, bool coarsen_boundary) { cout << "coarsen_cell: " << cellid << endl; cout << "num_cells: " << mesh.num_cells() << endl; const std::size_t num_vertices = mesh.size(0); const std::size_t num_cells = mesh.size(mesh.topology().dim()); auto _mesh = reference_to_no_delete_pointer(mesh); // Initialise forbidden vertices MeshFunction<bool> vertex_forbidden(_mesh); vertex_forbidden.init(0); for (VertexIterator v(mesh); !v.end(); ++v) vertex_forbidden[v->index()] = false; // Initialise boundary vertices MeshFunction<bool> vertex_boundary(_mesh); vertex_boundary.init(0); for (VertexIterator v(mesh); !v.end(); ++v) vertex_boundary[v->index()] = false; BoundaryMesh boundary(mesh, "exterior"); MeshFunction<std::size_t>& bnd_vertex_map = boundary.entity_map(0); for (VertexIterator v(boundary); !v.end(); ++v) vertex_boundary[bnd_vertex_map[v->index()]] = true; // If coarsen boundary is forbidden if (coarsen_boundary == false) { for (VertexIterator v(boundary); !v.end(); ++v) vertex_forbidden[bnd_vertex_map[v->index()]] = true; } // Initialise data for finding which vertex to remove bool _collapse_edge = false; const unsigned int* edge_vertex; std::size_t shortest_edge_index = 0; double lmin, l; std::size_t num_cells_to_remove = 0; // Get cell type const CellType& cell_type = mesh.type(); const Cell cell(mesh, cellid); MeshEditor editor; editor.open(coarse_mesh, cell_type.cell_type(), mesh.topology().dim(), mesh.geometry().dim()); MeshFunction<bool> cell_to_remove(_mesh); cell_to_remove.init(mesh.topology().dim()); for (CellIterator ci(mesh); !ci.end(); ++ci) cell_to_remove[ci->index()] = false; MeshFunction<bool> cell_to_regenerate(_mesh); cell_to_regenerate.init(mesh.topology().dim()); for (CellIterator ci(mesh); !ci.end(); ++ci) cell_to_regenerate[ci->index()] = false; // Find shortest edge of cell c _collapse_edge = false; lmin = 1.0e10*cell.diameter(); for (EdgeIterator e(cell); !e.end(); ++e) { edge_vertex = e->entities(0); if (!vertex_forbidden[edge_vertex[0]] || !vertex_forbidden[edge_vertex[1]]) { l = e->length(); if ( lmin > l ) { lmin = l; shortest_edge_index = e->index(); _collapse_edge = true; } } } Edge shortest_edge(mesh, shortest_edge_index); // Decide which vertex to remove std::size_t vert2remove_idx = 0; // If at least one vertex should be removed if ( _collapse_edge == true ) { edge_vertex = shortest_edge.entities(0); if(vertex_forbidden[edge_vertex[0]] && vertex_forbidden[edge_vertex[1]]) { // Both vertices are forbidden, cannot coarsen cout << "both vertices forbidden" << endl; editor.close(); return false; } if(vertex_forbidden[edge_vertex[0]] == true) vert2remove_idx = edge_vertex[1]; else if(vertex_forbidden[edge_vertex[1]] == true) vert2remove_idx = edge_vertex[0]; else if(vertex_boundary[edge_vertex[1]] == true && vertex_boundary[edge_vertex[0]] == false) vert2remove_idx = edge_vertex[0]; else if(vertex_boundary[edge_vertex[0]] == true && vertex_boundary[edge_vertex[1]] == false) vert2remove_idx = edge_vertex[1]; else if ( edge_vertex[0] > edge_vertex[1] ) vert2remove_idx = edge_vertex[0]; else vert2remove_idx = edge_vertex[1]; } else { // No vertices to remove, cannot coarsen cout << "all vertices forbidden" << endl; editor.close(); return false; } Vertex vertex_to_remove(mesh, vert2remove_idx); // Remove cells around edge num_cells_to_remove = 0; for (CellIterator cn(shortest_edge); !cn.end(); ++cn) { cell_to_remove[cn->index()] = true; num_cells_to_remove++; // Update cell map old2new_cell[cn->index()] = -1; } // Regenerate cells around vertex for (CellIterator cn(vertex_to_remove); !cn.end(); ++cn) { cell_to_regenerate[cn->index()] = true; // Update cell map (will be filled in with correct index) old2new_cell[cn->index()] = -1; } // Specify number of vertices and cells editor.init_vertices_global(num_vertices - 1, num_vertices - 1); editor.init_cells_global(num_cells - num_cells_to_remove, num_cells - num_cells_to_remove); cout << "Number of cells in old mesh: " << num_cells << "; to remove: " << num_cells_to_remove << endl; // Add old vertices std::size_t vertex = 0; for(VertexIterator v(mesh); !v.end(); ++v) { if(vertex_to_remove.index() == v->index()) old2new_vertex[v->index()] = -1; else { //cout << "adding old vertex at: " << v->point() << endl; old2new_vertex[v->index()] = vertex; editor.add_vertex(vertex, v->point()); vertex++; } } // Add old unrefined cells std::size_t cv_idx; std::size_t current_cell = 0; std::vector<std::size_t> cell_vertices(cell_type.num_entities(0)); for (CellIterator c(mesh); !c.end(); ++c) { if (cell_to_remove[*c] == false && cell_to_regenerate[*c] == false) { cv_idx = 0; for (VertexIterator v(*c); !v.end(); ++v) cell_vertices[cv_idx++] = old2new_vertex[v->index()]; //cout << "adding old cell" << endl; editor.add_cell(current_cell++, cell_vertices); // Update cell maps old2new_cell[c->index()] = current_cell - 1; } } // Add new cells. collapse_edge(mesh, shortest_edge, vertex_to_remove, cell_to_remove, old2new_vertex, old2new_cell, editor, current_cell); editor.close(); // Set volume tolerance. This parameter determines a quality criterion // for the new mesh: higher value indicates a sharper criterion. double vol_tol = 1.0e-3; bool mesh_ok = true; Cell removed_cell(mesh, cellid); // Check mesh quality (volume) for (CellIterator c(removed_cell); !c.end(); ++c) { std::size_t id = c->index(); int nid = old2new_cell[id]; if(nid != -1) { Cell cn(coarse_mesh, nid); double qm = cn.volume() / cn.diameter(); if(qm < vol_tol) { warning("Cell quality too low"); cout << "qm: " << qm << endl; mesh_ok = false; return mesh_ok; } } } // Checking for inverted cells for (CellIterator c(removed_cell); !c.end(); ++c) { std::size_t id = c->index(); int nid = old2new_cell[id]; if(nid != -1) { Cell cn(coarse_mesh, nid); if(c->orientation() != cn.orientation()) { cout << "cell orientation inverted" << endl; mesh_ok = false; return mesh_ok; } } } return mesh_ok; }
//----------------------------------------------------------------------------- void UniformMeshRefinement::refine(Mesh& refined_mesh, const Mesh& mesh) { not_working_in_parallel("UniformMeshRefinement::refine"); log(TRACE, "Refining simplicial mesh uniformly."); // Check that refined_mesh and mesh are not the same if (&refined_mesh == &mesh) { dolfin_error("UniformMeshRefinement.cpp", "refine mesh", "Refined_mesh and mesh point to the same object"); } // Generate cell - edge connectivity if not generated mesh.init(mesh.topology().dim(), 1); // Generate edge - vertex connectivity if not generated mesh.init(1, 0); // Mesh needs to be ordered (so we can pick right combination of vertices/edges) if (!mesh.ordered()) dolfin_error("UniformMeshRefinement.cpp", "refine mesh", "Mesh is not ordered according to the UFC numbering convention, consider calling mesh.order()"); // Get cell type const CellType& cell_type = mesh.type(); // Open new mesh for editing MeshEditor editor; editor.open(refined_mesh, cell_type.cell_type(), mesh.topology().dim(), mesh.geometry().dim()); // Get size of mesh const std::size_t num_vertices = mesh.size(0); const std::size_t num_edges = mesh.size(1); const std::size_t num_cells = mesh.size(mesh.topology().dim()); // Specify number of vertices and cells editor.init_vertices_global(num_vertices + num_edges, num_vertices + num_edges); editor.init_cells_global(ipow(2, mesh.topology().dim())*num_cells, ipow(2, mesh.topology().dim())*num_cells); // Add old vertices std::size_t vertex = 0; for (VertexIterator v(mesh); !v.end(); ++v) { editor.add_vertex(vertex, v->point()); vertex++; } // Add new vertices for (EdgeIterator e(mesh); !e.end(); ++e) { editor.add_vertex(vertex, e->midpoint()); vertex++; } // Add cells std::size_t current_cell = 0; for (CellIterator c(mesh); !c.end(); ++c) cell_type.refine_cell(*c, editor, current_cell); // Close editor editor.close(); // Make sure that mesh is ordered after refinement //refined_mesh.order(); }
//----------------------------------------------------------------------------- void IntervalMesh::build(std::size_t nx, double a, double b) { // Receive mesh according to parallel policy if (MPI::is_receiver(this->mpi_comm())) { MeshPartitioning::build_distributed_mesh(*this); return; } if (std::abs(a - b) < DOLFIN_EPS) { dolfin_error("Interval.cpp", "create interval", "Length of interval is zero. Consider checking your dimensions"); } if (b < a) { dolfin_error("Interval.cpp", "create interval", "Length of interval is negative. Consider checking the order of your arguments"); } if (nx < 1) { dolfin_error("Interval.cpp", "create interval", "Number of points on interval is (%d), it must be at least 1", nx); } rename("mesh", "Mesh of the interval (a, b)"); // Open mesh for editing MeshEditor editor; editor.open(*this, CellType::interval, 1, 1); // Create vertices and cells: editor.init_vertices_global((nx+1), (nx+1)); editor.init_cells_global(nx, nx); // Create main vertices: for (std::size_t ix = 0; ix <= nx; ix++) { const std::vector<double> x(1, a + (static_cast<double>(ix)*(b - a)/static_cast<double>(nx))); editor.add_vertex(ix, x); } // Create intervals for (std::size_t ix = 0; ix < nx; ix++) { std::vector<std::size_t> cell(2); cell[0] = ix; cell[1] = ix + 1; editor.add_cell(ix, cell); } // Close mesh editor editor.close(); // Broadcast mesh according to parallel policy if (MPI::is_broadcaster(this->mpi_comm())) { std::cout << "Building mesh (dist 0a)" << std::endl; MeshPartitioning::build_distributed_mesh(*this); std::cout << "Building mesh (dist 1a)" << std::endl; return; } }
//----------------------------------------------------------------------------- UnitHexMesh::UnitHexMesh(MPI_Comm comm, std::size_t nx, std::size_t ny, std::size_t nz) : Mesh(comm) { // Receive mesh according to parallel policy if (MPI::is_receiver(this->mpi_comm())) { MeshPartitioning::build_distributed_mesh(*this); return; } MeshEditor editor; editor.open(*this, CellType::hexahedron, 3, 3); // Create vertices and cells: editor.init_vertices_global((nx + 1)*(ny + 1)*(nz + 1), (nx + 1)*(ny + 1)*(nz + 1)); editor.init_cells_global(nx*ny*nz, nx*ny*nz); // Storage for vertices std::vector<double> x(3); const double a = 0.0; const double b = 1.0; const double c = 0.0; const double d = 1.0; const double e = 0.0; const double f = 1.0; // Create main vertices: std::size_t vertex = 0; for (std::size_t iz = 0; iz <= nz; iz++) { x[2] = e + ((static_cast<double>(iz))*(f - e)/static_cast<double>(nz)); for (std::size_t iy = 0; iy <= ny; iy++) { x[1] = c + ((static_cast<double>(iy))*(d - c)/static_cast<double>(ny)); for (std::size_t ix = 0; ix <= nx; ix++) { x[0] = a + ((static_cast<double>(ix))*(b - a)/static_cast<double>(nx)); editor.add_vertex(vertex, x); vertex++; } } } // Create cuboids std::size_t cell = 0; std::vector<std::size_t> v(8); for (std::size_t iz = 0; iz < nz; iz++) for (std::size_t iy = 0; iy < ny; iy++) for (std::size_t ix = 0; ix < nx; ix++) { v[0] = (iz*(ny + 1) + iy)*(nx + 1) + ix; v[1] = v[0] + 1; v[2] = v[0] + (nx + 1); v[3] = v[1] + (nx + 1); v[4] = v[0] + (nx + 1)*(ny + 1); v[5] = v[1] + (nx + 1)*(ny + 1); v[6] = v[2] + (nx + 1)*(ny + 1); v[7] = v[3] + (nx + 1)*(ny + 1); editor.add_cell(cell, v); ++cell; } // Close mesh editor editor.close(); // Broadcast mesh according to parallel policy if (MPI::is_broadcaster(this->mpi_comm())) { MeshPartitioning::build_distributed_mesh(*this); return; } }
//----------------------------------------------------------------------------- void XMLMesh::read_mesh(Mesh& mesh, const pugi::xml_node mesh_node) { // Get cell type and geometric dimension const std::string cell_type_str = mesh_node.attribute("celltype").value(); const std::size_t gdim = mesh_node.attribute("dim").as_uint(); // Get topological dimension boost::scoped_ptr<CellType> cell_type(CellType::create(cell_type_str)); const std::size_t tdim = cell_type->dim(); // Create mesh for editing MeshEditor editor; editor.open(mesh, cell_type_str, tdim, gdim); // Get vertices xml node pugi::xml_node xml_vertices = mesh_node.child("vertices"); dolfin_assert(xml_vertices); // Get number of vertices and init editor const std::size_t num_vertices = xml_vertices.attribute("size").as_uint(); editor.init_vertices_global(num_vertices, num_vertices); // Iterate over vertices and add to mesh Point p; for (pugi::xml_node_iterator it = xml_vertices.begin(); it != xml_vertices.end(); ++it) { const std::size_t index = it->attribute("index").as_uint(); p[0] = it->attribute("x").as_double(); p[1] = it->attribute("y").as_double(); p[2] = it->attribute("z").as_double(); editor.add_vertex(index, p); } // Get cells node pugi::xml_node xml_cells = mesh_node.child("cells"); dolfin_assert(xml_cells); // Get number of cells and init editor const std::size_t num_cells = xml_cells.attribute("size").as_uint(); editor.init_cells_global(num_cells, num_cells); // Create list of vertex index attribute names const unsigned int num_vertices_per_cell = cell_type->num_vertices(tdim); std::vector<std::string> v_str(num_vertices_per_cell); for (std::size_t i = 0; i < num_vertices_per_cell; ++i) v_str[i] = "v" + boost::lexical_cast<std::string, unsigned int>(i); // Iterate over cells and add to mesh std::vector<std::size_t> v(num_vertices_per_cell); for (pugi::xml_node_iterator it = xml_cells.begin(); it != xml_cells.end(); ++it) { const std::size_t index = it->attribute("index").as_uint(); for (unsigned int i = 0; i < num_vertices_per_cell; ++i) v[i] = it->attribute(v_str[i].c_str()).as_uint(); editor.add_cell(index, v); } // Close mesh editor editor.close(); }
//----------------------------------------------------------------------------- dolfin::Mesh MeshRenumbering::renumber_by_color(const Mesh& mesh, const std::vector<std::size_t> coloring_type) { // Start timer Timer timer("Renumber mesh by color"); // Get some some mesh const std::size_t tdim = mesh.topology().dim(); const std::size_t gdim = mesh.geometry().dim(); const std::size_t num_local_vertices = mesh.size(0); const std::size_t num_global_vertices = mesh.size_global(0); const std::size_t num_local_cells = mesh.size(tdim); const std::size_t num_global_cells = mesh.size_global(tdim); // Check that requested coloring is a cell coloring if (coloring_type[0] != tdim) { dolfin_error("MeshRenumbering.cpp", "renumber mesh by color", "Coloring is not a cell coloring: only cell colorings are supported"); } // Compute renumbering std::vector<double> new_coordinates; std::vector<std::size_t> new_connections; MeshRenumbering::compute_renumbering(mesh, coloring_type, new_coordinates, new_connections); // Create new mesh Mesh new_mesh; // Create mesh editor MeshEditor editor; editor.open(new_mesh, mesh.type().cell_type(), tdim, gdim); editor.init_cells_global(num_local_cells, num_global_cells); editor.init_vertices_global(num_local_vertices, num_global_vertices); // Add vertices dolfin_assert(new_coordinates.size() == num_local_vertices*gdim); for (std::size_t i = 0; i < num_local_vertices; ++i) { std::vector<double> x(gdim); for (std::size_t j = 0; j < gdim; ++j) x[j] = new_coordinates[i*gdim + j]; editor.add_vertex(i, x); } cout << "Done adding vertices" << endl; // Add cells dolfin_assert(new_coordinates.size() == num_local_vertices*gdim); const std::size_t vertices_per_cell = mesh.type().num_entities(0); for (std::size_t i = 0; i < num_local_cells; ++i) { std::vector<std::size_t> c(vertices_per_cell); std::copy(new_connections.begin() + i*vertices_per_cell, new_connections.begin() + i*vertices_per_cell + vertices_per_cell, c.begin()); editor.add_cell(i, c); } editor.close(); cout << "Close editor" << endl; // Initialise coloring data typedef std::map<std::vector<std::size_t>, std::pair<std::vector<std::size_t>, std::vector<std::vector<std::size_t>>>>::const_iterator ConstMeshColoringData; // Get old coloring ConstMeshColoringData mesh_coloring = mesh.topology().coloring.find(coloring_type); if (mesh_coloring == mesh.topology().coloring.end()) { dolfin_error("MeshRenumbering.cpp", "renumber mesh by color", "Requested mesh coloring has not been computed"); } // Get old coloring data const std::vector<std::size_t>& colors = mesh_coloring->second.first; const std::vector<std::vector<std::size_t>>& entities_of_color = mesh_coloring->second.second; dolfin_assert(colors.size() == num_local_cells); dolfin_assert(!entities_of_color.empty()); const std::size_t num_colors = entities_of_color.size(); // New coloring data dolfin_assert(new_mesh.topology().coloring.empty()); std::vector<std::size_t> new_colors(colors.size()); std::vector<std::vector<std::size_t>> new_entities_of_color(num_colors); std::size_t current_cell = 0; for (std::size_t color = 0; color < num_colors; color++) { // Get the array of cell indices of current color const std::vector<std::size_t>& colored_cells = entities_of_color[color]; std::vector<std::size_t>& new_colored_cells = new_entities_of_color[color]; // Update cell color data for (std::size_t i = 0; i < colored_cells.size(); i++) { new_colored_cells.push_back(current_cell); new_colors[current_cell] = color; current_cell++; } } // Set new coloring mesh data std::pair<ConstMeshColoringData, bool> insert = new_mesh.topology().coloring.insert(std::make_pair(coloring_type, std::make_pair(new_colors, new_entities_of_color))); dolfin_assert(insert.second); cout << "Return new mesh" << endl; return new_mesh; }
//----------------------------------------------------------------------------- void RectangleMesh::build(const Point& p0, const Point& p1, std::size_t nx, std::size_t ny, std::string diagonal) { // Receive mesh according to parallel policy if (MPI::is_receiver(this->mpi_comm())) { MeshPartitioning::build_distributed_mesh(*this); return; } // Check options if (diagonal != "left" && diagonal != "right" && diagonal != "right/left" && diagonal != "left/right" && diagonal != "crossed") { dolfin_error("RectangleMesh.cpp", "create rectangle", "Unknown mesh diagonal definition: allowed options are \"left\", \"right\", \"left/right\", \"right/left\" and \"crossed\""); } // Extract minimum and maximum coordinates const double x0 = std::min(p0.x(), p1.x()); const double x1 = std::max(p0.x(), p1.x()); const double y0 = std::min(p0.y(), p1.y()); const double y1 = std::max(p0.y(), p1.y()); const double a = x0; const double b = x1; const double c = y0; const double d = y1; if (std::abs(x0 - x1) < DOLFIN_EPS || std::abs(y0 - y1) < DOLFIN_EPS) { dolfin_error("Rectangle.cpp", "create rectangle", "Rectangle seems to have zero width, height or depth. Consider checking your dimensions"); } if (nx < 1 || ny < 1) { dolfin_error("RectangleMesh.cpp", "create rectangle", "Rectangle has non-positive number of vertices in some dimension: number of vertices must be at least 1 in each dimension"); } rename("mesh", "Mesh of the unit square (a,b) x (c,d)"); // Open mesh for editing MeshEditor editor; editor.open(*this, CellType::triangle, 2, 2); // Create vertices and cells: if (diagonal == "crossed") { editor.init_vertices_global((nx + 1)*(ny + 1) + nx*ny, (nx + 1)*(ny + 1) + nx*ny); editor.init_cells_global(4*nx*ny, 4*nx*ny); } else { editor.init_vertices_global((nx + 1)*(ny + 1), (nx + 1)*(ny + 1)); editor.init_cells_global(2*nx*ny, 2*nx*ny); } // Storage for vertices std::vector<double> x(2); // Create main vertices: std::size_t vertex = 0; for (std::size_t iy = 0; iy <= ny; iy++) { x[1] = c + ((static_cast<double>(iy))*(d - c)/static_cast<double>(ny)); for (std::size_t ix = 0; ix <= nx; ix++) { x[0] = a + ((static_cast<double>(ix))*(b - a)/static_cast<double>(nx)); editor.add_vertex(vertex, x); vertex++; } } // Create midpoint vertices if the mesh type is crossed if (diagonal == "crossed") { for (std::size_t iy = 0; iy < ny; iy++) { x[1] = c +(static_cast<double>(iy) + 0.5)*(d - c)/static_cast<double>(ny); for (std::size_t ix = 0; ix < nx; ix++) { x[0] = a + (static_cast<double>(ix) + 0.5)*(b - a)/static_cast<double>(nx); editor.add_vertex(vertex, x); vertex++; } } } // Create triangles std::size_t cell = 0; if (diagonal == "crossed") { boost::multi_array<std::size_t, 2> cells(boost::extents[4][3]); for (std::size_t iy = 0; iy < ny; iy++) { for (std::size_t ix = 0; ix < nx; ix++) { const std::size_t v0 = iy*(nx + 1) + ix; const std::size_t v1 = v0 + 1; const std::size_t v2 = v0 + (nx + 1); const std::size_t v3 = v1 + (nx + 1); const std::size_t vmid = (nx + 1)*(ny + 1) + iy*nx + ix; // Note that v0 < v1 < v2 < v3 < vmid. cells[0][0] = v0; cells[0][1] = v1; cells[0][2] = vmid; cells[1][0] = v0; cells[1][1] = v2; cells[1][2] = vmid; cells[2][0] = v1; cells[2][1] = v3; cells[2][2] = vmid; cells[3][0] = v2; cells[3][1] = v3; cells[3][2] = vmid; // Add cells for (auto _cell = cells.begin(); _cell != cells.end(); ++_cell) editor.add_cell(cell++, *_cell); } } } else if (diagonal == "left" || diagonal == "right" || diagonal == "right/left" || diagonal == "left/right") { std::string local_diagonal = diagonal; boost::multi_array<std::size_t, 2> cells(boost::extents[2][3]); for (std::size_t iy = 0; iy < ny; iy++) { // Set up alternating diagonal if (diagonal == "right/left") { if (iy % 2) local_diagonal = "right"; else local_diagonal = "left"; } if (diagonal == "left/right") { if (iy % 2) local_diagonal = "left"; else local_diagonal = "right"; } for (std::size_t ix = 0; ix < nx; ix++) { const std::size_t v0 = iy*(nx + 1) + ix; const std::size_t v1 = v0 + 1; const std::size_t v2 = v0 + (nx + 1); const std::size_t v3 = v1 + (nx + 1); std::vector<std::size_t> cell_data; if(local_diagonal == "left") { cells[0][0] = v0; cells[0][1] = v1; cells[0][2] = v2; cells[1][0] = v1; cells[1][1] = v2; cells[1][2] = v3; if (diagonal == "right/left" || diagonal == "left/right") local_diagonal = "right"; } else { cells[0][0] = v0; cells[0][1] = v1; cells[0][2] = v3; cells[1][0] = v0; cells[1][1] = v2; cells[1][2] = v3; if (diagonal == "right/left" || diagonal == "left/right") local_diagonal = "left"; } editor.add_cell(cell++, cells[0]); editor.add_cell(cell++, cells[1]); } } } // Close mesh editor editor.close(); // Broadcast mesh according to parallel policy if (MPI::is_broadcaster(this->mpi_comm())) { MeshPartitioning::build_distributed_mesh(*this); return; } }
//----------------------------------------------------------------------------- void SubMesh::init(const Mesh& mesh, const std::vector<std::size_t>& sub_domains, std::size_t sub_domain) { // Open mesh for editing MeshEditor editor; const std::size_t D = mesh.topology().dim(); editor.open(*this, mesh.type().cell_type(), D, mesh.geometry().dim()); // Build set of cells that are in sub-mesh std::vector<bool> parent_cell_in_subdomain(mesh.num_cells(), false); std::set<std::size_t> submesh_cells; for (CellIterator cell(mesh); !cell.end(); ++cell) { if (sub_domains[cell->index()] == sub_domain) { parent_cell_in_subdomain[cell->index()] = true; submesh_cells.insert(cell->index()); } } // Map from parent vertex index to submesh vertex index std::map<std::size_t, std::size_t> parent_to_submesh_vertex_indices; // Map from submesh cell to parent cell std::vector<std::size_t> submesh_cell_parent_indices; submesh_cell_parent_indices.reserve(submesh_cells.size()); // Vector from parent cell index to submesh cell index std::vector<std::size_t> parent_to_submesh_cell_indices(mesh.num_cells(), 0); // Add sub-mesh cells editor.init_cells_global(submesh_cells.size(), submesh_cells.size()); std::size_t current_cell = 0; std::size_t current_vertex = 0; for (std::set<std::size_t>::iterator cell_it = submesh_cells.begin(); cell_it != submesh_cells.end(); ++cell_it) { // Data structure to hold new vertex indices for cell std::vector<std::size_t> cell_vertices; // Create cell Cell cell(mesh, *cell_it); // Iterate over cell vertices for (VertexIterator vertex(cell); !vertex.end(); ++vertex) { const std::size_t parent_vertex_index = vertex->index(); // Look for parent vertex in map std::map<std::size_t, std::size_t>::iterator vertex_it = parent_to_submesh_vertex_indices.find(parent_vertex_index); // If vertex has been inserted, get new index, otherwise // increment and insert std::size_t submesh_vertex_index = 0; if (vertex_it != parent_to_submesh_vertex_indices.end()) submesh_vertex_index = vertex_it->second; else { submesh_vertex_index = current_vertex++; parent_to_submesh_vertex_indices[parent_vertex_index] = submesh_vertex_index; } // Add vertex to list of cell vertices (new indexing) cell_vertices.push_back(submesh_vertex_index); } // Add parent cell index to list submesh_cell_parent_indices.push_back(cell.index()); // Store parent cell -> submesh cell indices parent_to_submesh_cell_indices[cell.index()] = current_cell; // Add cell to mesh editor.add_cell(current_cell++, cell_vertices); } // Vector to hold submesh vertex -> parent vertex std::vector<std::size_t> parent_vertex_indices; parent_vertex_indices.resize(parent_to_submesh_vertex_indices.size()); // Initialise mesh editor editor.init_vertices_global(parent_to_submesh_vertex_indices.size(), parent_to_submesh_vertex_indices.size()); // Add vertices for (std::map<std::size_t, std::size_t>::iterator it = parent_to_submesh_vertex_indices.begin(); it != parent_to_submesh_vertex_indices.end(); ++it) { Vertex vertex(mesh, it->first); if (MPI::size(mesh.mpi_comm()) > 1) error("SubMesh::init not working in parallel"); // FIXME: Get global vertex index editor.add_vertex(it->second, vertex.point()); parent_vertex_indices[it->second] = it->first; } // Close editor editor.close(); // Build submesh-to-parent map for vertices std::vector<std::size_t>& parent_vertex_indices_mf = data().create_array("parent_vertex_indices", 0); parent_vertex_indices_mf.resize(num_vertices()); for (std::map<std::size_t, std::size_t>::iterator it = parent_to_submesh_vertex_indices.begin(); it != parent_to_submesh_vertex_indices.end(); ++it) { parent_vertex_indices_mf[it->second] = it->first; } // Build submesh-to-parent map for cells std::vector<std::size_t>& parent_cell_indices = data().create_array("parent_cell_indices", D); parent_cell_indices.resize(num_cells()); current_cell = 0; for (std::vector<std::size_t>::iterator it = submesh_cell_parent_indices.begin(); it != submesh_cell_parent_indices.end(); ++it) { parent_cell_indices[current_cell++] = *it; } // Initialise present MeshDomain const MeshDomains& parent_domains = mesh.domains(); this->domains().init(parent_domains.max_dim()); // Collect MeshValueCollections from parent mesh for (std::size_t dim_t = 0; dim_t <= parent_domains.max_dim(); dim_t++) { // If parent mesh does not has a data for dim_t if (parent_domains.num_marked(dim_t) == 0) continue; // Initialise connectivity mesh.init(dim_t, D); // FIXME: Can avoid building this map for cell and vertices // Build map from submesh entity (parent vertex list) -> (submesh index) mesh.init(dim_t); std::map<std::vector<std::size_t>, std::size_t> entity_map; for (MeshEntityIterator e(*this, dim_t); !e.end(); ++e) { // Build list of entity vertex indices and sort std::vector<std::size_t> vertex_list; for (VertexIterator v(*e); !v.end(); ++v) vertex_list.push_back(parent_vertex_indices[v->index()]); std::sort(vertex_list.begin(), vertex_list.end()); entity_map.insert(std::make_pair(vertex_list, e->index())); } // Get submesh marker map std::map<std::size_t, std::size_t>& submesh_markers = this->domains().markers(dim_t); // Get values map from parent MeshValueCollection const std::map<std::size_t, std::size_t>& parent_markers = parent_domains.markers(dim_t); // Iterate over all parents marker values std::map<std::size_t, std::size_t>::const_iterator itt; for (itt = parent_markers.begin(); itt != parent_markers.end(); itt++) { // Create parent entity const MeshEntity parent_entity(mesh, dim_t, itt->first); // FIXME: Need to check all attached cells std::size_t parent_cell_index = std::numeric_limits<std::size_t>::max(); if (dim_t == D) { parent_cell_index = itt->first; } else { // Get first parent cell index attached to parent entity for (std::size_t i = 0; i < parent_entity.num_entities(D); ++i) { if (sub_domains[parent_entity.entities(D)[i]] == sub_domain) { parent_cell_index = parent_entity.entities(D)[i]; break; } } } // Check if the cell is included in the submesh if (sub_domains[parent_cell_index] == sub_domain) { // Map markers from parent mesh to submesh if (dim_t == D) { // Get submesh cell index const std::size_t submesh_cell_index = parent_to_submesh_cell_indices[parent_cell_index]; submesh_markers[submesh_cell_index] = itt->second; } else { std::vector<std::size_t> parent_vertex_list; for (VertexIterator v(parent_entity); !v.end(); ++v) parent_vertex_list.push_back(v->index()); std::sort(parent_vertex_list.begin(), parent_vertex_list.end()); // Get submesh entity index std::map<std::vector<std::size_t>, std::size_t>::const_iterator submesh_it = entity_map.find(parent_vertex_list); dolfin_assert(submesh_it != entity_map.end()); submesh_markers[submesh_it->second] = itt->second; } } } } }