Mesh build_mesh(const std::vector<unsigned int>& cells, const std::vector<double>& vertices, int dim) { // vertices and cells are flattened unsigned int vlen = vertices.size() / dim; unsigned int clen = cells.size() / (dim + 1); Mesh mesh; MeshEditor editor; editor.open(mesh, dim, dim); editor.init_vertices(vlen); editor.init_cells(clen); if (dim==3) { for (int i=0; i<vlen; i++) editor.add_vertex(i, vertices[3*i], vertices[3*i+1], vertices[3*i+2]); for (int i=0; i<clen; i++) editor.add_cell(i, cells[4*i], cells[4*i+1], cells[4*i+2], cells[4*i+3]); } else { for (int i=0; i<vlen; i++) editor.add_vertex(i, vertices[2*i], vertices[2*i+1]); for (int i=0; i<clen; i++) editor.add_cell(i, cells[3*i], cells[3*i+1], cells[3*i+2]); } editor.close(); return mesh; }
//----------------------------------------------------------------------------- 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 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(); }
//----------------------------------------------------------------------------- void DynamicMeshEditor::close(bool order) { dolfin_assert(_mesh); dolfin_assert(_cell_type); // Open default mesh editor MeshEditor editor; editor.open(*_mesh, _cell_type->cell_type(), _tdim, _gdim); // Set number of vertices const std::size_t num_vertices = vertex_coordinates.size()/_gdim; editor.init_vertices(num_vertices); // Set number of cells const std::size_t vertices_per_cell = _cell_type->num_vertices(_gdim); const std::size_t num_cells = cell_vertices.size()/vertices_per_cell; editor.init_cells(num_cells); // Add vertices std::vector<double> p(_gdim); for (std::size_t v = 0; v < num_vertices; v++) { const std::size_t offset = v*_gdim; for (std::size_t i = 0; i < _gdim; i++) p[i] = vertex_coordinates[offset + i]; editor.add_vertex(v, p); } // Add cells std::vector<std::size_t> vertices(vertices_per_cell); for (std::size_t c = 0; c < num_cells; c++) { const std::size_t offset = c*vertices_per_cell; for (std::size_t i = 0; i < vertices_per_cell; i++) vertices[i] = cell_vertices[offset + i]; editor.add_cell(c, vertices); } // Close editor editor.close(order); // Clear data clear(); }
//----------------------------------------------------------------------------- void ParallelRefinement::build_local(Mesh& new_mesh) const { MeshEditor ed; const std::size_t tdim = _mesh.topology().dim(); const std::size_t gdim = _mesh.geometry().dim(); dolfin_assert(new_vertex_coordinates.size()%gdim == 0); const std::size_t num_vertices = new_vertex_coordinates.size()/gdim; const std::size_t num_cell_vertices = tdim + 1; dolfin_assert(new_cell_topology.size()%num_cell_vertices == 0); const std::size_t num_cells = new_cell_topology.size()/num_cell_vertices; ed.open(new_mesh, tdim, gdim); ed.init_vertices(num_vertices); std::size_t i = 0; for (auto p = new_vertex_coordinates.begin(); p != new_vertex_coordinates.end(); p += gdim) { std::vector<double> vertex(p, p + gdim); ed.add_vertex(i, vertex); ++i; } ed.init_cells(num_cells); i = 0; std::vector<std::size_t> cell(num_cell_vertices); for (auto p = new_cell_topology.begin(); p != new_cell_topology.end(); p += num_cell_vertices) { std::copy(p, p + num_cell_vertices, cell.begin()); ed.add_cell(i, cell); ++i; } ed.close(); }
//----------------------------------------------------------------------------- UnitDiscMesh::UnitDiscMesh(MPI_Comm comm, std::size_t n, std::size_t degree, std::size_t gdim) : Mesh(comm) { dolfin_assert(n > 0); dolfin_assert(gdim == 2 or gdim == 3); dolfin_assert(degree == 1 or degree == 2); MeshEditor editor; editor.open(*this, 2, gdim, degree); editor.init_vertices_global(1 + 3*n*(n + 1), 1 + 3*n*(n + 1)); std::size_t c = 0; editor.add_vertex(c, Point(0,0,0)); ++c; for (std::size_t i = 1; i <= n; ++i) for (std::size_t j = 0; j < 6*i; ++j) { double r = (double)i/(double)n; double th = 2*M_PI*(double)j/(double)(6*i); double x = r*cos(th); double y = r*sin(th); editor.add_vertex(c, Point(x, y, 0)); ++c; } editor.init_cells(6*n*n); c = 0; std::size_t base_i = 0; std::size_t row_i = 1; for (std::size_t i = 1; i <= n; ++i) { std::size_t base_m = base_i; base_i = 1 + 3*i*(i - 1); std::size_t row_m = row_i; row_i = 6*i; for (std::size_t k = 0; k != 6; ++k) for (std::size_t j = 0; j < (i*2 - 1); ++j) { std::size_t i0, i1, i2; if (j%2 == 0) { i0 = base_i + (k*i + j/2)%row_i; i1 = base_i + (k*i + j/2 + 1)%row_i; i2 = base_m + (k*(i-1) + j/2)%row_m; } else { i0 = base_m + (k*(i-1) + j/2)%row_m; i1 = base_m + (k*(i-1) + j/2 + 1)%row_m; i2 = base_i + (k*i + j/2 + 1)%row_i; } editor.add_cell(c, i0, i1, i2); ++c; } } // Initialise entities required for this degree polynomial mesh // and allocate space for the point coordinate data if (degree == 2) { editor.init_entities(); for (EdgeIterator e(*this); !e.end(); ++e) { Point v0 = Vertex(*this, e->entities(0)[0]).point(); Point v1 = Vertex(*this, e->entities(0)[1]).point(); Point pt = e->midpoint(); if (std::abs(v0.norm() - 1.0) < 1e-6 and std::abs(v1.norm() - 1.0) < 1e-6) pt *= v0.norm()/pt.norm(); // Add Edge-based point editor.add_entity_point(1, 0, e->index(), pt); } } editor.close(); }
//----------------------------------------------------------------------------- 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(); }
//----------------------------------------------------------------------------- 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_vertices = mesh.num_vertices(); const std::size_t num_cells = mesh.num_cells(); // 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(num_cells); editor.init_vertices(num_vertices); // Add vertices dolfin_assert(new_coordinates.size() == num_vertices*gdim); for (std::size_t i = 0; i < num_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_vertices*gdim); const std::size_t vertices_per_cell = mesh.type().num_entities(0); for (std::size_t i = 0; i < num_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<const 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_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 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 RegularCutRefinement::refine_marked(Mesh& refined_mesh, const Mesh& mesh, const std::vector<int>& refinement_markers, const IndexSet& marked_edges) { // Count the number of cells in refined mesh std::size_t num_cells = 0; // Data structure to hold a cell std::vector<std::size_t> cell_data(3); for (CellIterator cell(mesh); !cell.end(); ++cell) { const int marker = refinement_markers[cell->index()]; switch (marker) { case no_refinement: num_cells += 1; break; case regular_refinement: num_cells += 4; break; case backtrack_bisection: num_cells += 2; break; case backtrack_bisection_refine: num_cells += 3; break; default: num_cells += 2; } } // Initialize mesh editor const std::size_t num_vertices = mesh.num_vertices() + marked_edges.size(); MeshEditor editor; editor.open(refined_mesh, mesh.topology().dim(), mesh.geometry().dim()); editor.init_vertices(num_vertices); editor.init_cells(num_cells); // Set vertex coordinates std::size_t current_vertex = 0; for (VertexIterator vertex(mesh); !vertex.end(); ++vertex) { editor.add_vertex(current_vertex, vertex->point()); current_vertex++; } for (std::size_t i = 0; i < marked_edges.size(); i++) { Edge edge(mesh, marked_edges[i]); editor.add_vertex(current_vertex, edge.midpoint()); current_vertex++; } // Get bisection data for old mesh const std::size_t D = mesh.topology().dim(); const std::vector<std::size_t>* bisection_twins = NULL; if (mesh.data().exists("bisection_twins", D)) bisection_twins = &(mesh.data().array("bisection_twins", D)); // Markers for bisected cells pointing to their bisection twins in // refined mesh std::vector<std::size_t>& refined_bisection_twins = refined_mesh.data().create_array("bisection_twins", D); refined_bisection_twins.resize(num_cells); for (std::size_t i = 0; i < num_cells; i++) refined_bisection_twins[i] = i; // Mapping from old to new unrefined cells (-1 means refined or not // yet processed) std::vector<int> unrefined_cells(mesh.num_cells()); std::fill(unrefined_cells.begin(), unrefined_cells.end(), -1); // Iterate over all cells and add new cells std::size_t current_cell = 0; std::vector<std::vector<std::size_t> > cells(4, std::vector<std::size_t>(3)); for (CellIterator cell(mesh); !cell.end(); ++cell) { // Get marker const int marker = refinement_markers[cell->index()]; if (marker == no_refinement) { // No refinement: just copy cell to new mesh std::vector<std::size_t> vertices; for (VertexIterator vertex(*cell); !vertex.end(); ++vertex) vertices.push_back(vertex->index()); editor.add_cell(current_cell++, vertices); // Store mapping to new cell index unrefined_cells[cell->index()] = current_cell - 1; // Remember unrefined bisection twins if (bisection_twins) { const std::size_t bisection_twin = (*bisection_twins)[cell->index()]; const int twin_marker = refinement_markers[bisection_twin]; dolfin_assert(twin_marker == no_refinement); if (unrefined_cells[bisection_twin] >= 0) { const std::size_t i = current_cell - 1; const std::size_t j = unrefined_cells[bisection_twin]; refined_bisection_twins[i] = j; refined_bisection_twins[j] = i; } } } else if (marker == regular_refinement) { // Regular refinement: divide into subsimplicies dolfin_assert(unrefined_cells[cell->index()] == -1); // Get vertices and edges const unsigned int* v = cell->entities(0); const unsigned int* e = cell->entities(1); dolfin_assert(v); dolfin_assert(e); // Get offset for new vertex indices const std::size_t offset = mesh.num_vertices(); // Compute indices for the six new vertices const std::size_t v0 = v[0]; const std::size_t v1 = v[1]; const std::size_t v2 = v[2]; const std::size_t e0 = offset + marked_edges.find(e[0]); const std::size_t e1 = offset + marked_edges.find(e[1]); const std::size_t e2 = offset + marked_edges.find(e[2]); // Create four new cells cells[0][0] = v0; cells[0][1] = e2; cells[0][2] = e1; cells[1][0] = v1; cells[1][1] = e0; cells[1][2] = e2; cells[2][0] = v2; cells[2][1] = e1; cells[2][2] = e0; cells[3][0] = e0; cells[3][1] = e1; cells[3][2] = e2; // Add cells std::vector<std::vector<std::size_t> >::const_iterator _cell; for (_cell = cells.begin(); _cell != cells.end(); ++_cell) editor.add_cell(current_cell++, *_cell); } else if (marker == backtrack_bisection || marker == backtrack_bisection_refine) { // Special case: backtrack bisected cells dolfin_assert(unrefined_cells[cell->index()] == -1); // Get index for bisection twin dolfin_assert(bisection_twins); const std::size_t bisection_twin = (*bisection_twins)[cell->index()]; dolfin_assert(bisection_twin != cell->index()); // Let lowest number twin handle refinement if (bisection_twin < cell->index()) continue; // Get marker for twin const int twin_marker = refinement_markers[bisection_twin]; // Find common edge(s) and bisected edge(s) const std::pair<std::size_t, std::size_t> common_edges = find_common_edges(*cell, mesh, bisection_twin); const std::pair<std::size_t, std::size_t> bisection_edges = find_bisection_edges(*cell, mesh, bisection_twin); const std::pair<std::size_t, std::size_t> bisection_vertices = find_bisection_vertices(*cell, mesh, bisection_twin, bisection_edges); // Get list of vertices and edges for both cells const Cell twin(mesh, bisection_twin); const unsigned int* vertices_0 = cell->entities(0); const unsigned int* vertices_1 = twin.entities(0); const unsigned int* edges_0 = cell->entities(1); const unsigned int* edges_1 = twin.entities(1); dolfin_assert(vertices_0); dolfin_assert(vertices_1); dolfin_assert(edges_0); dolfin_assert(edges_1); // Get offset for new vertex indices const std::size_t offset = mesh.num_vertices(); // Locate vertices such that v_i is the vertex opposite to // the edge e_i on the parent triangle const std::size_t v0 = vertices_0[common_edges.first]; const std::size_t v1 = vertices_1[common_edges.second]; const std::size_t v2 = vertices_0[bisection_edges.first]; const std::size_t e0 = offset + marked_edges.find(edges_1[bisection_vertices.second]); const std::size_t e1 = offset + marked_edges.find(edges_0[bisection_vertices.first]); const std::size_t e2 = vertices_0[bisection_vertices.first]; // Locate new vertices on bisected edge (if any) std::size_t E0 = 0; std::size_t E1 = 0; if (marker == backtrack_bisection_refine) E0 = offset + marked_edges.find(edges_0[bisection_edges.first]); if (twin_marker == backtrack_bisection_refine) E1 = offset + marked_edges.find(edges_1[bisection_edges.second]); // Add middle two cells (always) dolfin_assert(cell_data.size() == 3); cell_data[0] = e0; cell_data[1] = e1; cell_data[2] = e2; editor.add_cell(current_cell++, cell_data); cell_data[0] = v2; cell_data[1] = e1; cell_data[2] = e0; editor.add_cell(current_cell++, cell_data); // Add one or two remaining cells in current cell (left) if (marker == backtrack_bisection) { cell_data[0] = v0; cell_data[1] = e2; cell_data[2] = e1; editor.add_cell(current_cell++, cell_data); } else { // Add the two cells cell_data[0] = v0; cell_data[1] = E0; cell_data[2] = e1; editor.add_cell(current_cell++, cell_data); cell_data[0] = E0; cell_data[1] = e2; cell_data[2] = e1; editor.add_cell(current_cell++, cell_data); // Set bisection twins refined_bisection_twins[current_cell - 2] = current_cell - 1; refined_bisection_twins[current_cell - 1] = current_cell - 2; } // Add one or two remaining cells in twin cell (right) if (twin_marker == backtrack_bisection) { cell_data[0] = v1; cell_data[1] = e0; cell_data[2] = e2; editor.add_cell(current_cell++, cell_data); } else { // Add the two cells cell_data[0] = v1; cell_data[1] = e0; cell_data[2] = E1; editor.add_cell(current_cell++, cell_data); cell_data[0] = e0; cell_data[1] = e2; cell_data[2] = E1; editor.add_cell(current_cell++, cell_data); // Set bisection twins refined_bisection_twins[current_cell - 2] = current_cell - 1; refined_bisection_twins[current_cell - 1] = current_cell - 2; } } else { // One edge marked for refinement: do bisection dolfin_assert(unrefined_cells[cell->index()] == -1); // Get vertices and edges const unsigned int* v = cell->entities(0); const unsigned int* e = cell->entities(1); dolfin_assert(v); dolfin_assert(e); // Get edge number (equal to marker) dolfin_assert(marker >= 0); const std::size_t local_edge_index = static_cast<std::size_t>(marker); const std::size_t global_edge_index = e[local_edge_index]; const std::size_t ee = mesh.num_vertices() + marked_edges.find(global_edge_index); // Add the two new cells if (local_edge_index == 0) { cell_data[0] = v[0]; cell_data[1] = ee; cell_data[2] = v[1]; editor.add_cell(current_cell++, cell_data); cell_data[0] = v[0]; cell_data[1] = ee; cell_data[2] = v[2]; editor.add_cell(current_cell++, cell_data); } else if (local_edge_index == 1) { cell_data[0] = v[1]; cell_data[1] = ee; cell_data[2] = v[0]; editor.add_cell(current_cell++, cell_data); cell_data[0] = v[1]; cell_data[1] = ee; cell_data[2] = v[2]; editor.add_cell(current_cell++, cell_data); } else { cell_data[0] = v[2]; cell_data[1] = ee; cell_data[2] = v[0]; editor.add_cell(current_cell++, cell_data); cell_data[0] = v[2]; cell_data[1] = ee; cell_data[2] = v[1]; editor.add_cell(current_cell++, cell_data); } // Set bisection twins refined_bisection_twins[current_cell - 2] = current_cell - 1; refined_bisection_twins[current_cell - 1] = current_cell - 2; } } // Close mesh editor dolfin_assert(num_cells == current_cell); editor.close(); }
//----------------------------------------------------------------------------- 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(); }
//----------------------------------------------------------------------------- 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; } } } } }