예제 #1
0
//-----------------------------------------------------------------------------
void DofMap::set(GenericVector& x, double value) const
{
  std::vector<double> _value;
  std::vector<std::vector<dolfin::la_index> >::const_iterator cell_dofs;
  for (cell_dofs = _dofmap.begin(); cell_dofs != _dofmap.end(); ++cell_dofs)
  {
    _value.resize(cell_dofs->size(), value);
    x.set(_value.data(), cell_dofs->size(), cell_dofs->data());
  }
  x.apply("add");
}
예제 #2
0
//-----------------------------------------------------------------------------
void DofMap::set(GenericVector& x, double value) const
{
  dolfin_assert(_dofmap.size() % _cell_dimension == 0);
  const std::size_t num_cells = _dofmap.size() / _cell_dimension;

  std::vector<double> _value(_cell_dimension, value);
  for (std::size_t i = 0; i < num_cells; ++i)
  {
    const ArrayView<const la_index> dofs = cell_dofs(i);
    x.set_local(_value.data(), dofs.size(), dofs.data());
  }
  x.apply("insert");
}
예제 #3
0
//-----------------------------------------------------------------------------
void PointSource::apply(GenericVector& b)
{
  dolfin_assert(_V);

  log(PROGRESS, "Applying point source to right-hand side vector.");

  // Find the cell containing the point (may be more than one cell but
  // we only care about the first). Well-defined if the basis
  // functions are continuous but may give unexpected results for DG.
  dolfin_assert(_V->mesh());
  const Mesh& mesh = *_V->mesh();
  std::shared_ptr<BoundingBoxTree> tree = mesh.bounding_box_tree();
  const unsigned int cell_index = tree->compute_first_entity_collision(_p);

  // Check that we found the point on at least one processor
  int num_found = 0;
  if (cell_index == std::numeric_limits<unsigned int>::max())
    num_found = MPI::sum(mesh.mpi_comm(), 0);
  else
    num_found = MPI::sum(mesh.mpi_comm(), 1);
  if (MPI::rank(mesh.mpi_comm()) == 0 && num_found == 0)
  {
    dolfin_error("PointSource.cpp",
                 "apply point source to vector",
                 "The point is outside of the domain (%s)", _p.str().c_str());
  }

  // Return if point not found
  if (cell_index == std::numeric_limits<unsigned int>::max())
  {
    b.apply("add");
    return;
  }

  // Create cell
  const Cell cell(mesh, static_cast<std::size_t>(cell_index));

  // Vertex coordinates
  const std::size_t gdim = mesh.geometry().dim();
  const std::size_t num_vertices = cell.num_entities(0);
  std::vector<double> vertex_coordinates(gdim* num_vertices);
  const unsigned int* vertices = cell.entities(0);
  for (std::size_t i = 0; i < num_vertices; i++)
    for (std::size_t j = 0; j < gdim; j++)
      vertex_coordinates[i*gdim + j] = mesh.geometry().x(vertices[i])[j];

  // Evaluate all basis functions at the point()
  dolfin_assert(_V->element());
  dolfin_assert(_V->element()->value_rank() == 0);
  std::vector<double> values(_V->element()->space_dimension());
  const int cell_orientation = 0;
  _V->element()->evaluate_basis_all(values.data(),
                                   _p.coordinates(),
                                    vertex_coordinates.data(),
                                    cell_orientation);

  // Scale by magnitude
  for (std::size_t i = 0; i < _V->element()->space_dimension(); i++)
    values[i] *= _magnitude;

  // Compute local-to-global mapping
  dolfin_assert(_V->dofmap());
  const std::vector<dolfin::la_index>& dofs
    = _V->dofmap()->cell_dofs(cell.index());

  // Add values to vector
  dolfin_assert(_V->element()->space_dimension()
                == _V->dofmap()->cell_dimension(cell.index()));
  b.add(values.data(), _V->element()->space_dimension(), dofs.data());
  b.apply("add");
}
예제 #4
0
//-----------------------------------------------------------------------------
void FunctionSpace::interpolate(GenericVector& expansion_coefficients,
                                const GenericFunction& v) const
{
  dolfin_assert(_mesh);
  dolfin_assert(_element);
  dolfin_assert(_dofmap);

  // Check that function ranks match
  if (_element->value_rank() != v.value_rank())
  {
    dolfin_error("FunctionSpace.cpp",
                 "interpolate function into function space",
                 "Rank of function (%d) does not match rank of function space (%d)",
                 v.value_rank(), element()->value_rank());
  }

  // Check that function dims match
  for (std::size_t i = 0; i < _element->value_rank(); ++i)
  {
    if (_element->value_dimension(i) != v.value_dimension(i))
    {
      dolfin_error("FunctionSpace.cpp",
                   "interpolate function into function space",
                   "Dimension %d of function (%d) does not match dimension %d of function space (%d)",
                   i, v.value_dimension(i), i, element()->value_dimension(i));
    }
  }

  // Initialize vector of expansion coefficients
  if (expansion_coefficients.size() != _dofmap->global_dimension())
  {
    dolfin_error("FunctionSpace.cpp",
                 "interpolate function into function space",
                 "Wrong size of vector");
  }
  expansion_coefficients.zero();

  // Initialize local arrays
  std::vector<double> cell_coefficients(_dofmap->max_element_dofs());

  // Iterate over mesh and interpolate on each cell
  ufc::cell ufc_cell;
  std::vector<double> vertex_coordinates;
  for (CellIterator cell(*_mesh); !cell.end(); ++cell)
  {
    // Update to current cell
    cell->get_vertex_coordinates(vertex_coordinates);
    cell->get_cell_data(ufc_cell);

    // Restrict function to cell
    v.restrict(cell_coefficients.data(), *_element, *cell,
               vertex_coordinates.data(), ufc_cell);

    // Tabulate dofs
    const ArrayView<const dolfin::la_index> cell_dofs
      = _dofmap->cell_dofs(cell->index());

    // Copy dofs to vector
    expansion_coefficients.set_local(cell_coefficients.data(),
                                     _dofmap->num_element_dofs(cell->index()),
                                     cell_dofs.data());
  }

  // Finalise changes
  expansion_coefficients.apply("insert");
}
예제 #5
0
//-----------------------------------------------------------------------------
std::size_t MUMPSLUSolver::solve(GenericVector& x, const GenericVector& b)
{
  dolfin_assert(_matA);

  DMUMPS_STRUC_C data;

  data.comm_fortran = -987654;

  // Initialise
  data.job = -1;

  // Host participates in solve
  data.par = 1;

  // Output related parameters
  //data.ICNTL(1) = 6; // error messages
  //data.ICNTL(2) = 0;
  //data.ICNTL(3) = 6; // Global information
  //data.ICNTL(3) = 6; // Global information
  if (parameters["verbose"])
    data.ICNTL(4) = 2;
  else
    data.ICNTL(4) = 1;

  // Matrix symmetry (0=non-symmetric, 2=symmetric positive defn, 2=symmetric)
  data.sym = 0;
  if (parameters["symmetric"])
    data.sym = 2;

  // Initialise MUMPS
  dmumps_c(&data);

  // Related to use of ScaLAPACK (+/-. Negative is faster?)
  //data.ICNTL(13) = -1;

  // Solve transpose (1: A x = b, otherwise A^T x = b)
  data.ICNTL(9) = 1;

  // FIXME (20=default)
  data.ICNTL(14) = 20;

  // Reordering (7=automatic)
  data.ICNTL(7) = 7;

  // Control solution vector (0=solution on root, 1=solution distributed)
  data.ICNTL(21) = 1;

  // Distributed matrix
  data.ICNTL(18) = 3;

  // Parallel/serial analysis (0=auto, 1=serial, 2=parallel)
  if (MPI::size(_matA->mpi_comm()) > 1)
    data.ICNTL(28) = 2;
  else
    data.ICNTL(28) = 0;

  // Parallel graph partitioning library (0=auto, 1=pt-scotch, 2=parmetis)
  data.ICNTL(29) = 0;

  // Global size
  dolfin_assert(_matA->size(0) == _matA->size(1));
  data.n = _matA->size(0);

  if (!_matA->base_one())
    dolfin_error("MUMPSLUSolver.cpp",
                 "initialize solver",
                 "MUMPS requires a CoordinateMatrix with Fortran-style "
                 "base 1 indexing");

  // Get matrix coordinate and value data
  const std::vector<std::size_t>& rows = _matA->rows();
  const std::vector<std::size_t>& cols = _matA->columns();
  const std::vector<double>& vals = _matA->values();

  // Number of non-zero entries on this process
  data.nz_loc = rows.size();

  // Pass matrix data to MUMPS. Trust MUMPS not to change it
  data.irn_loc = const_cast<int*>(reinterpret_cast<const int*>(rows.data()));
  data.jcn_loc = const_cast<int*>(reinterpret_cast<const int*>(cols.data()));
  data.a_loc   = const_cast<double*>(vals.data());

  // Analyse and factorize
  data.job = 4;
  dmumps_c(&data);
  if (data.INFOG(1) < 0)
    dolfin_error("MUMPSLUSolver.cpp",
                 "compute matrix factors",
                 "MUMPS reported an error during the analysis and "
                 "factorisation");

  cout << "Factorisation finished" << endl;

  // Gather RHS on root process and attach
  std::vector<double> _b;
  b.gather_on_zero(_b);
  data.rhs = _b.data();

  // Scaling strategy (77 is default)
  data.ICNTL(8) = 77;

  // Get size of local solution vector x and create objects to hold solution
  const std::size_t local_x_size = data.INFO(23);
  std::vector<int> x_local_indices(local_x_size);
  std::vector<double> x_local_vals(local_x_size);

  // Attach solution data to MUMPS object
  data.lsol_loc = local_x_size;
  data.sol_loc  = x_local_vals.data();
  data.isol_loc = x_local_indices.data();

  // Solve problem
  data.job = 3;
  dmumps_c(&data);
  if (data.INFOG(1) < 0)
    dolfin_error("MUMPSLUSolver.cpp",
                 "compute matrix factors",
                 "MUMPS reported an error during the solve");

  // Shift indices by -1
  for (std::size_t i = 0; i < local_x_size ; ++i)
    x_local_indices[i]--;

  // Set x values
  #if defined(PETSC_USE_64BIT_INDICES)
  // Cast indices to 64 bit
  std::vector<dolfin::la_index> _x_local_indices(x_local_indices.begin(),
                                                 x_local_indices.end());
  x.set_local(x_local_vals.data(), x_local_indices.size(),
              _x_local_indices.data());
  #else
  x.set_local(x_local_vals.data(), x_local_indices.size(),
              x_local_indices.data());
  #endif
  x.apply("insert");

  // Clean up
  data.job = -2;
  dmumps_c(&data);

  return 1;
}
예제 #6
0
//-----------------------------------------------------------------------------
void NewDirichletBC::apply(GenericMatrix& A, GenericVector& b,
                const GenericVector* x, const DofMap& dof_map, const ufc::form& form)
{
  bool reassemble = dolfin_get("PDE reassemble matrix");
  std::cout << "newdirichlet: " << reassemble << std::endl;

  // FIXME: How do we reuse the dof map for u?

  if (method == topological)
    message("Applying Dirichlet boundary conditions to linear system.");
  /*
  else if (method == geometrical)
    message("Applying Dirichlet boundary conditions to linear system (geometrical approach).");
  else
    message("Applying Dirichlet boundary conditions to linear system (pointwise approach).");
  */
  // Make sure we have the facet - cell connectivity
  const uint D = _mesh.topology().dim();
  if (method == topological)
    _mesh.init(D - 1, D);

  // Create local data for application of boundary conditions
  BoundaryCondition::LocalData data(form, _mesh, dof_map, sub_system);
  
  // A map to hold the mapping from boundary dofs to boundary values
  std::map<uint, real> boundary_values;

  if (method == pointwise)
  {
    Progress p("Applying Dirichlet boundary conditions", _mesh.size(D));
    for (CellIterator cell(_mesh); !cell.end(); ++cell)
    {
      computeBCPointwise(boundary_values, *cell, data);
      p++;
    }
  }
  else
  {
    // Iterate over the facets of the mesh
    Progress p("Applying Dirichlet boundary conditions", _mesh.size(D - 1));
    for (FacetIterator facet(_mesh); !facet.end(); ++facet)
    {
      // Skip facets not inside the sub domain
      if ((*sub_domains)(*facet) != sub_domain)
      {
        p++;
        continue;
      }

      // Chose strategy
      if (method == topological)
        computeBCTopological(boundary_values, *facet, data);
      else
        computeBCGeometrical(boundary_values, *facet, data);
    
      // Update process
      p++;
    }
  }

  // Copy boundary value data to arrays
  uint* dofs = new uint[boundary_values.size()];
  real* values = new real[boundary_values.size()];
  std::map<uint, real>::const_iterator boundary_value;
  uint i = 0;
  for (boundary_value = boundary_values.begin(); boundary_value != boundary_values.end(); ++boundary_value)
  {
    dofs[i]     = boundary_value->first;
    values[i++] = boundary_value->second;
  }

  // Modify boundary values for nonlinear problems
  if (x)
  {
    real* x_values = new real[boundary_values.size()];
    x->get(x_values, boundary_values.size(), dofs);
    for (uint i = 0; i < boundary_values.size(); i++)
      values[i] -= x_values[i];
    delete[] x_values;
  }
  
  // Modify RHS vector (b[i] = value)
  b.set(values, boundary_values.size(), dofs);

  if(reassemble)
  {
    // Modify linear system (A_ii = 1)
    A.ident(boundary_values.size(), dofs);
  }

  // Clear temporary arrays
  delete [] dofs;
  delete [] values;

  // Finalise changes to b
  b.apply();
}
예제 #7
0
//----------------------------------------------------------------------------
void LocalSolver::solve(GenericVector& x, const Form& a, const Form& L,
                        bool symmetric) const
{
  UFC ufc_a(a);
  UFC ufc_L(L);

  // Set timer
  Timer timer("Local solver");

  // Extract mesh
  const Mesh& mesh = a.mesh();

  // Form ranks
  const std::size_t rank_a = ufc_a.form.rank();
  const std::size_t rank_L = ufc_L.form.rank();

  // Check form ranks
  dolfin_assert(rank_a == 2);
  dolfin_assert(rank_L == 1);

  // Collect pointers to dof maps
  std::shared_ptr<const GenericDofMap> dofmap_a0
    = a.function_space(0)->dofmap();
  std::shared_ptr<const GenericDofMap> dofmap_a1
    = a.function_space(1)->dofmap();
  std::shared_ptr<const GenericDofMap> dofmap_L
    = a.function_space(0)->dofmap();
  dolfin_assert(dofmap_a0);
  dolfin_assert(dofmap_a1);
  dolfin_assert(dofmap_L);

  // Initialise vector
  if (x.empty())
  {
    std::pair<std::size_t, std::size_t> local_range
      = dofmap_L->ownership_range();
    x.init(mesh.mpi_comm(), local_range);
  }

  // Cell integrals
  ufc::cell_integral* integral_a = ufc_a.default_cell_integral.get();
  ufc::cell_integral* integral_L = ufc_L.default_cell_integral.get();

  // Eigen data structures
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> A;
  Eigen::VectorXd b, x_local;

  // Assemble over cells
  Progress p("Performing local (cell-wise) solve", mesh.num_cells());
  ufc::cell ufc_cell;
  std::vector<double> vertex_coordinates;
  for (CellIterator cell(mesh); !cell.end(); ++cell)
  {
    // Update to current cell
    cell->get_vertex_coordinates(vertex_coordinates);
    cell->get_cell_data(ufc_cell);
    ufc_a.update(*cell, vertex_coordinates, ufc_cell,
                 integral_a->enabled_coefficients());
    ufc_L.update(*cell, vertex_coordinates, ufc_cell,
                 integral_L->enabled_coefficients());

    // Get local-to-global dof maps for cell
    const std::vector<dolfin::la_index>& dofs_a0
      = dofmap_a0->cell_dofs(cell->index());
    const std::vector<dolfin::la_index>& dofs_a1
      = dofmap_a1->cell_dofs(cell->index());
    const std::vector<dolfin::la_index>& dofs_L
      = dofmap_L->cell_dofs(cell->index());

    // Check that local problem is square and a and L match
    dolfin_assert(dofs_a0.size() == dofs_a1.size());
    dolfin_assert(dofs_a1.size() == dofs_L.size());

    // Resize A and b
    A.resize(dofs_a0.size(), dofs_a1.size());
    b.resize(dofs_L.size());

    // Tabulate A and b on cell
    integral_a->tabulate_tensor(A.data(),
                                ufc_a.w(),
                                vertex_coordinates.data(),
                                ufc_cell.orientation);
    integral_L->tabulate_tensor(b.data(),
                                ufc_L.w(),
                                vertex_coordinates.data(),
                                ufc_cell.orientation);

    // Solve local problem
    x_local = A.partialPivLu().solve(b);

    // Set solution in global vector
    x.set(x_local.data(), dofs_a0.size(), dofs_a0.data());

    p++;
  }

  // Finalise vector
  x.apply("insert");
}
예제 #8
0
//-----------------------------------------------------------------------------
void DirichletBC::zero_columns(GenericMatrix& A,
                               GenericVector& b,
                               double diag_val) const
{
  // Check arguments
  check_arguments(&A, &b, NULL, 1);

  // A map to hold the mapping from boundary dofs to boundary values
  Map bv_map;
  get_boundary_values(bv_map);

  // Create lookup table of dofs
  //const std::size_t nrows = A.size(0); // should be equal to b.size()
  const std::size_t ncols = A.size(1); // should be equal to max possible dof+1

  std::pair<std::size_t, std::size_t> rows = A.local_range(0);

  std::vector<char> is_bc_dof(ncols);
  std::vector<double> bc_dof_val(ncols);
  for (Map::const_iterator bv = bv_map.begin(); bv != bv_map.end(); ++bv)
  {
    is_bc_dof[bv->first] = 1;
    bc_dof_val[bv->first] = bv->second;
  }

  // Scan through all columns of all rows, setting to zero if
  // is_bc_dof[column]. At the same time, we collect corrections to
  // the RHS

  std::vector<std::size_t> cols;
  std::vector<double> vals;
  std::vector<double> b_vals;
  std::vector<dolfin::la_index> b_rows;

  for (std::size_t row = rows.first; row < rows.second; row++)
  {
    // If diag_val is nonzero, the matrix is a diagonal block
    // (nrows==ncols), and we can set the whole BC row
    if (diag_val != 0.0 && is_bc_dof[row])
    {
      A.getrow(row, cols, vals);
      for (std::size_t j = 0; j < cols.size(); j++)
        vals[j] = (cols[j] == row)*diag_val;
      A.setrow(row, cols, vals);
      A.apply("insert");
      b.setitem(row, bc_dof_val[row]*diag_val);
    }
    else // Otherwise, we scan the row for BC columns
    {
      A.getrow(row, cols, vals);
      bool row_changed = false;
      for (std::size_t j = 0; j < cols.size(); j++)
      {
        const std::size_t col = cols[j];

        // Skip columns that aren't BC, and entries that are zero
        if (!is_bc_dof[col] || vals[j] == 0.0)
          continue;

        // We're going to change the row, so make room for it
        if (!row_changed)
        {
          row_changed = true;
          b_rows.push_back(row);
          b_vals.push_back(0.0);
        }

        b_vals.back() -= bc_dof_val[col]*vals[j];
        vals[j] = 0.0;
      }
      if (row_changed)
      {
        A.setrow(row, cols, vals);
        A.apply("insert");
      }
    }
  }

  b.add_local(&b_vals.front(), b_rows.size(), &b_rows.front());
  b.apply("add");
}
예제 #9
0
//----------------------------------------------------------------------------
void LocalSolver::solve_local(GenericVector& x, const GenericVector& b,
                              const GenericDofMap& dofmap_b) const
{
  dolfin_assert(_a);
  dolfin_assert(_a->rank() == 2);

  // Extract mesh
  dolfin_assert(_a->function_space(0)->mesh());
  const Mesh& mesh = *_a->function_space(0)->mesh();

  // Check whether to use cache for factorizations
  const bool use_cache
    = _cholesky_cache.empty() and _lu_cache.empty() ? false : true;

  // Create UFC object
  UFC ufc_a(*_a);

  // Get cell integral
  std::shared_ptr<ufc::cell_integral> integral_a = ufc_a.default_cell_integral;
  dolfin_assert(integral_a);

  // Get dofmaps
  std::array<std::shared_ptr<const GenericDofMap>, 2> dofmaps_a
    = {{_a->function_space(0)->dofmap(), _a->function_space(1)->dofmap()}};
  dolfin_assert(dofmaps_a[0] and dofmaps_a[1]);

  // Check dimensions
  dolfin_assert(dofmaps_a[0]->global_dimension()
                == dofmaps_a[1]->global_dimension());
  dolfin_assert(dofmaps_a[0]->global_dimension()
                == dofmap_b.global_dimension());

  // Eigen data structures for local tensors
  Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> A_e;
  Eigen::VectorXd b_e, x_e;

  // Eigen factorizations
  Eigen::PartialPivLU<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
                                    Eigen::RowMajor>> lu;
  Eigen::LLT<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
                           Eigen::RowMajor>> cholesky;

  // Assemble LHS over cells and solve
  Progress p("Performing local (cell-wise) solve", mesh.num_cells());
  ufc::cell ufc_cell;
  std::vector<double> vertex_coordinates;
  for (CellIterator cell(mesh); !cell.end(); ++cell)
  {
    // Get cell dofmaps
    const ArrayView<const dolfin::la_index> dofs_L
      = dofmap_b.cell_dofs(cell->index());
    const ArrayView<const dolfin::la_index> dofs_a0
      = dofmaps_a[0]->cell_dofs(cell->index());

    // Check dimensions
    dolfin_assert(dofs_L.size() == dofs_a0.size());

    // Copy global RHS data into local RHS
    b_e.resize(dofs_L.size());
    b.get_local(b_e.data(), dofs_L.size(), dofs_L.data());

    // Solve local problem
    if (!use_cache)
    {
      // Update to current cell
      cell->get_vertex_coordinates(vertex_coordinates);
      cell->get_cell_data(ufc_cell);

      // Update LHS UFC object
      ufc_a.update(*cell, vertex_coordinates, ufc_cell,
                   integral_a->enabled_coefficients());

      // Resize A_e and tabulate on for cell
      const std::size_t dim = dofmaps_a[0]->num_element_dofs(cell->index());
      dolfin_assert(dim == dofmaps_a[1]->num_element_dofs(cell->index()));
      A_e.resize(dim, dim);
      integral_a->tabulate_tensor(A_e.data(), ufc_a.w(),
                                  vertex_coordinates.data(),
                                  ufc_cell.orientation);
      // Solve local problem
      if (_solver_type == SolverType::Cholesky)
      {
        cholesky.compute(A_e);
        x_e = cholesky.solve(b_e);
      }
      else
      {
        lu.compute(A_e);
        x_e = lu.solve(b_e);
      }
    }
    else
    {
      if (_solver_type == SolverType::Cholesky)
        x_e = _cholesky_cache[cell->index()].solve(b_e);
      else
        x_e = _lu_cache[cell->index()].solve(b_e);
    }

    // Set solution in global vector
    x.set_local(x_e.data(), dofs_a0.size(), dofs_a0.data());

    p++;
  }

  // Finalise vector
  x.apply("insert");
}