Example #1
0
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;
}
Example #2
0
//-----------------------------------------------------------------------------
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();
}
Example #4
0
//-----------------------------------------------------------------------------
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;
  }
}
Example #5
0
//-----------------------------------------------------------------------------
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();

}
Example #6
0
//-----------------------------------------------------------------------------
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;
  }
}
Example #7
0
//-----------------------------------------------------------------------------
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();
}
Example #8
0
//-----------------------------------------------------------------------------
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();
}
Example #11
0
int main(int argc, char *argv[]) {
  
  if (argc < 3 ) {
    std::cout<< "Usage: ./extract <checkpoint> <num>" << std::endl;
    return 0;
  }
  
  std::ostringstream _fname;
  _fname << argv[1] << "_";

  std::vector<std::string> chkp_files;

  for (int i = 0; i <  atoi(argv[2]); i++) {
    std::ostringstream tmp;
    tmp << _fname.str();
    tmp << i << ".chkp";
    chkp_files.push_back(tmp.str());
  }
  

  CellType::Type type;
  double t;
  unsigned int id, tdim, gdim, num_vertices, num_cells, num_entities;
  std::ifstream in;
  std::list<dVertex> vlist;
  std::list<dCell> dmesh;
  for(std::vector<std::string>::iterator it = chkp_files.begin(); 
      it != chkp_files.end(); ++it) { 

    in.open(it->c_str(), std::ifstream::binary);

    if(in.good()) {
      in.read((char *)&id, sizeof(unsigned int));
      in.read((char *)&t, sizeof(double));
      
      in.read((char *)&type, sizeof(CellType::Type));
      in.read((char *)&tdim, sizeof(unsigned int));
      in.read((char *)&gdim, sizeof(unsigned int));

      in.read((char *)&num_vertices, sizeof(unsigned int));
      in.read((char *)&num_cells, sizeof(unsigned int));
      in.read((char *)&num_entities, sizeof(unsigned int));

      double *coords = new double[gdim *num_vertices];
      in.read((char *)coords, (gdim * num_vertices) * sizeof(double));
      
      std::list<dVertex> _vlist;
      int vi = 0;
      for(unsigned int i = 0; i < gdim * num_vertices; i += gdim) {
	switch(gdim)
	{
	case 2:
	  _vlist.push_back(dVertex(vi++,  Point(coords[i], coords[i+1]))); break;
	case 3:
	  _vlist.push_back(dVertex(vi++,  Point(coords[i], coords[i+1], coords[i+2]))); break;
	}
      }
      delete[] coords;

      unsigned int *cells = new unsigned int[num_entities * num_cells];
      in.read((char *)cells, (num_entities * num_cells) * sizeof(unsigned int));

      unsigned int *mapping = new unsigned int[_vlist.size()];
      in.read((char *)mapping, _vlist.size() * sizeof(unsigned int));

      unsigned int *mp = &mapping[0];
      std::map<unsigned int, unsigned int> vmap;      
      for(std::list<dVertex>::iterator it = _vlist.begin(); 
	  it != _vlist.end(); ++it) 
	vmap[it->id] = *(mp++);
      delete[] mapping;	
      
      Array<unsigned int> v;
      for(unsigned int i = 0; i < num_entities * num_cells; i += num_entities) {
	v.clear();
	for(unsigned int j = 0; j < num_entities; j++)
	  v.push_back(vmap[cells[i+j]]);
	dmesh.push_back(dCell(v));
      }
      delete[] cells;

      unsigned int num_ghost;
      in.read((char *)&num_ghost, sizeof(unsigned int));
      unsigned int *ghosts = new unsigned int[2 * num_ghost];
      in.read((char *)ghosts, 2*num_ghost * sizeof(unsigned int));
      
      std::set<unsigned int> ghost_set;
      for (unsigned int i = 0; i < 2 * num_ghost; i += 2)
	ghost_set.insert(ghosts[i]);
      delete[] ghosts;

      for(std::list<dVertex>::iterator it = _vlist.begin(); 
	  it != _vlist.end(); ++it) 
	if(ghost_set.find(it->id) == ghost_set.end()) 
	  vlist.push_back(dVertex(vmap[it->id], it->p));
    }
    in.close();
  }

  Mesh mesh;
  MeshEditor editor;
  editor.open(mesh, type, tdim, gdim);
  editor.initVertices(vlist.size());
  editor.initCells(dmesh.size());

  
  for(std::list<dVertex>::iterator it = vlist.begin(); it != vlist.end(); ++it)
    editor.addVertex(it->id, it->p);

  unsigned int ci = 0;
  for(std::list<dCell>::iterator it = dmesh.begin(); it != dmesh.end(); ++it)
    editor.addCell(ci++, it->vertices);
  
  editor.close();

  File mesh_file("mesh.xml");
  mesh_file << mesh;

}
Example #12
0
//-----------------------------------------------------------------------------
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;
}
Example #13
0
//-----------------------------------------------------------------------------
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;
	}
      }
    }
  }

}
Example #14
0
//-----------------------------------------------------------------------------
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 MeshPartitioning::build_mesh(Mesh& mesh,
              const std::vector<std::size_t>& global_cell_indices,
              const boost::multi_array<std::size_t, 2>& cell_global_vertices,
              const std::vector<std::size_t>& vertex_indices,
              const boost::multi_array<double, 2>& vertex_coordinates,
              const std::map<std::size_t, std::size_t>& vertex_global_to_local,
              std::size_t tdim, std::size_t gdim, std::size_t num_global_cells,
              std::size_t num_global_vertices)
{
  Timer timer("PARALLEL 3: Build mesh (from local mesh data)");

  // Get number of processes and process number
  const std::size_t num_processes = MPI::num_processes();
  const std::size_t process_number = MPI::process_number();

  // Open mesh for editing
  mesh.clear();
  MeshEditor editor;
  editor.open(mesh, tdim, gdim);

  // Add vertices
  editor.init_vertices(vertex_coordinates.size());
  Point point(gdim);
  dolfin_assert(vertex_indices.size() == vertex_coordinates.size());
  for (std::size_t i = 0; i < vertex_coordinates.size(); ++i)
  {
    for (std::size_t j = 0; j < gdim; ++j)
      point[j] = vertex_coordinates[i][j];
    editor.add_vertex_global(i, vertex_indices[i], point);
  }

  // Add cells
  editor.init_cells(cell_global_vertices.size());
  const std::size_t num_cell_vertices = tdim + 1;
  std::vector<std::size_t> cell(num_cell_vertices);
  for (std::size_t i = 0; i < cell_global_vertices.size(); ++i)
  {
    for (std::size_t j = 0; j < num_cell_vertices; ++j)
    {
      // Get local cell vertex
      std::map<std::size_t, std::size_t>::const_iterator iter
          = vertex_global_to_local.find(cell_global_vertices[i][j]);
      dolfin_assert(iter != vertex_global_to_local.end());
      cell[j] = iter->second;
    }
    editor.add_cell(i, global_cell_indices[i], cell);
  }

  // Close mesh: Note that this must be done after creating the global
  // vertex map or otherwise the ordering in mesh.close() will be wrong
  // (based on local numbers).
  editor.close();

  // Set global number of cells and vertices
  mesh.topology().init_global(0, num_global_vertices);
  mesh.topology().init_global(tdim,  num_global_cells);

  // Construct boundary mesh
  BoundaryMesh bmesh(mesh, "exterior");

  const MeshFunction<std::size_t>& boundary_vertex_map = bmesh.entity_map(0);
  const std::size_t boundary_size = boundary_vertex_map.size();

  // Build sorted array of global boundary vertex indices (global
  // numbering)
  std::vector<std::size_t> global_vertex_send(boundary_size);
  for (std::size_t i = 0; i < boundary_size; ++i)
    global_vertex_send[i] = vertex_indices[boundary_vertex_map[i]];
  std::sort(global_vertex_send.begin(), global_vertex_send.end());

  // Receive buffer
  std::vector<std::size_t> global_vertex_recv;

  // Create shared_vertices data structure: mapping from shared vertices
  // to list of neighboring processes
  std::map<unsigned int, std::set<unsigned int> >& shared_vertices
        = mesh.topology().shared_entities(0);
  shared_vertices.clear();

  // FIXME: Remove computation from inside communication loop

  // Build shared vertex to sharing processes map
  for (std::size_t i = 1; i < num_processes; ++i)
  {
    // We send data to process p - i (i steps to the left)
    const int p = (process_number - i + num_processes) % num_processes;

    // We receive data from process p + i (i steps to the right)
    const int q = (process_number + i) % num_processes;

    // Send and receive
    MPI::send_recv(global_vertex_send, p, global_vertex_recv, q);

    // Compute intersection of global indices
    std::vector<std::size_t> intersection(std::min(global_vertex_send.size(),
                                                   global_vertex_recv.size()));
    std::vector<std::size_t>::iterator intersection_end
      = std::set_intersection(global_vertex_send.begin(),
                              global_vertex_send.end(),
                              global_vertex_recv.begin(),
                              global_vertex_recv.end(),
                              intersection.begin());

    // Fill shared vertices information
    std::vector<std::size_t>::const_iterator global_index;
    for (global_index = intersection.begin(); global_index != intersection_end;
         ++global_index)
    {
      // Get local index
      std::map<std::size_t, std::size_t>::const_iterator local_index;
      local_index = vertex_global_to_local.find(*global_index);
      dolfin_assert(local_index != vertex_global_to_local.end());

      // Insert (local index, [proc])
      shared_vertices[local_index->second].insert(q);
    }
  }
}
Example #17
0
//-----------------------------------------------------------------------------
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();
}
Example #18
0
//-----------------------------------------------------------------------------
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;
  }
}