Exemplo n.º 1
0
//-----------------------------------------------------------------------------
void DirichletBC::zero(GenericMatrix& A) const
{
  // Check arguments
  check_arguments(&A, NULL, NULL, 0);

  // A map to hold the mapping from boundary dofs to boundary values
  Map boundary_values;

  // Create local data for application of boundary conditions
  dolfin_assert(_function_space);
  LocalData data(*_function_space);

  // Compute dofs and values
  compute_bc(boundary_values, data, _method);

  // Copy boundary value data to arrays
  std::vector<dolfin::la_index> dofs(boundary_values.size());
  std::size_t i = 0;
  for (auto bv = boundary_values.begin(); bv != boundary_values.end(); ++bv)
    dofs[i++] = bv->first;

  // Modify linear system (A_ii = 1)
  A.zero_local(boundary_values.size(), dofs.data());

  // Finalise changes to A
  A.apply("insert");
}
Exemplo n.º 2
0
  void compute_DG0_to_CG_weight_matrix(GenericMatrix& A, Function& DG)
  {
    compute_weight(DG);

    std::vector<std::size_t> columns;
    std::vector<double> values;
    std::vector<std::vector<std::size_t> > allcolumns;
    std::vector<std::vector<double> > allvalues;
        
    const std::pair<std::size_t, std::size_t> row_range = A.local_range(0);
    const std::size_t m = row_range.second - row_range.first;
    GenericVector& weight = *DG.vector();
    const std::pair<std::size_t, std::size_t> weight_range = weight.local_range();
    std::vector<std::size_t> weight_range_vec(2);
    weight_range_vec[0] = weight_range.first;
    weight_range_vec[1] = weight_range.second;
    int dm = weight_range.second-weight_range.first;
    
    const MPI_Comm mpi_comm = DG.function_space()->mesh()->mpi_comm();
        
    // Communicate local_ranges of weights
    std::vector<std::vector<std::size_t> > all_ranges;
    MPI::all_gather(mpi_comm, weight_range_vec, all_ranges);
    
    // Number of MPI processes
    std::size_t num_processes = MPI::size(mpi_comm);

    // Some weights live on other processes and need to be communicated
    // Create list of off-process weights
    std::vector<std::vector<std::size_t> > dofs_needed(num_processes);    
    for (std::size_t row = 0; row < m; row++)
    {   
      // Get global row number
      const std::size_t global_row = row + row_range.first;
      
      A.getrow(global_row, columns, values);
      
      for (std::size_t i = 0; i < columns.size(); i++)
      {
        std::size_t dof = columns[i];
        if (dof < weight_range.first || dof >= weight_range.second)
        {
          std::size_t owner = dof_owner(all_ranges, dof);
          dofs_needed[owner].push_back(dof);
        }
      }
    }

    // Communicate to all which weights are needed by the process
    std::vector<std::vector<std::size_t> > dofs_needed_recv;
    MPI::all_to_all(mpi_comm, dofs_needed, dofs_needed_recv);
    
    // Fetch the weights that must be communicated
    std::vector<std::vector<double> > weights_to_send(num_processes);    
    for (std::size_t p = 0; p < num_processes; p++)
    {
      if (p == MPI::rank(mpi_comm))  
        continue;
      
      std::vector<std::size_t> dofs = dofs_needed_recv[p];
      std::map<std::size_t, double> send_weights;
      for (std::size_t k = 0; k < dofs.size(); k++)
      {
        weights_to_send[p].push_back(weight[dofs[k]-weight_range.first]);
      }
    }
    std::vector<std::vector<double> > weights_to_send_recv;
    MPI::all_to_all(mpi_comm, weights_to_send, weights_to_send_recv);
    
    // Create a map for looking up received weights
    std::map<std::size_t, double> received_weights;
    for (std::size_t p = 0; p < num_processes; p++)
    {
      if (p == MPI::rank(mpi_comm))
        continue;
      
      for (std::size_t k = 0; k < dofs_needed[p].size(); k++)
      {
        received_weights[dofs_needed[p][k]] = weights_to_send_recv[p][k];         
      }
    }
    
    for (std::size_t row = 0; row < m; row++)
    {   
      // Get global row number
      const std::size_t global_row = row + row_range.first;
      
      A.getrow(global_row, columns, values);
      for (std::size_t i = 0; i < values.size(); i++)
      {
        std::size_t dof = columns[i];
        if (dof < weight_range.first || dof >= weight_range.second)
        {
          values[i] = received_weights[dof];
        }
        else
        {
          values[i] = weight[columns[i]-weight_range.first];  
        }
//        values[i] = 1./values[i];
      }
      
      double s = std::accumulate(values.begin(), values.end(), 0.0);
      std::transform(values.begin(), values.end(), values.begin(),
                     std::bind2nd(std::multiplies<double>(), 1./s));      

      for (std::size_t i=0; i<values.size(); i++)
      {
        double w;
        std::size_t dof = columns[i];
        if (dof < weight_range.first || dof >= weight_range.second)
        {
          w = received_weights[dof];
        }
        else
        {
          w = weight[dof-weight_range.first];  
        }        
        values[i] = values[i]*w;
//        values[i] = values[i]*values[i];
        
      }     
      
      allvalues.push_back(values);
      allcolumns.push_back(columns);
    }

    for (std::size_t row = 0; row < m; row++)
    {       
      // Get global row number
      const std::size_t global_row = row + row_range.first;
      
      A.setrow(global_row, allcolumns[row], allvalues[row]);
    }
    A.apply("insert");  
  }  
Exemplo n.º 3
0
// Base case for all divergence computations. 
// Compute divergence of vector field u.
void cr_divergence_matrix(GenericMatrix& M, GenericMatrix& A,
                       const FunctionSpace& DGscalar, 
                       const FunctionSpace& CRvector)
{
  std::shared_ptr<const GenericDofMap>
    CR1_dofmap = CRvector.dofmap(),
    DG0_dofmap = DGscalar.dofmap();

  // Figure out about the local dofs of DG0 
  std::pair<std::size_t, std::size_t>
  first_last_dof = DG0_dofmap->ownership_range();
  std::size_t first_dof = first_last_dof.first;
  std::size_t last_dof = first_last_dof.second;
  std::size_t n_local_dofs = last_dof - first_dof;

  // Get topological dimension so that we know what Facet is
  const Mesh mesh = *DGscalar.mesh();
  std::size_t tdim = mesh.topology().dim(); 
  std::size_t gdim = mesh.geometry().dim();
  
  std::vector<std::size_t> columns;
  std::vector<double> values;
  
  // Fill the values
  for(CellIterator cell(mesh); !cell.end(); ++cell)
  {
    auto dg_dofs = DG0_dofmap->cell_dofs(cell->index());
    // There is only one DG0 dof per cell
    dolfin::la_index cell_dof = dg_dofs[0];
    
    Point cell_mp = cell->midpoint();
    double cell_volume = cell->volume();
    std::size_t local_facet_index = 0;      
    
    auto cr_dofs = CR1_dofmap->cell_dofs(cell->index());
    
    for(FacetIterator facet(*cell); !facet.end(); ++facet)
    {
      double facet_measure=0;
      if(tdim == 2)
        facet_measure = Edge(mesh, facet->index()).length();
      else if(tdim == 3)
        facet_measure = Face(mesh, facet->index()).area();
      // Tdim 1 will not happen because CR is not defined there
      
      Point facet_normal = facet->normal();

      // Flip the normal if it is not outer already
      Point facet_mp = facet->midpoint();
      double sign = (facet_normal.dot(facet_mp - cell_mp) > 0.0) ? 1.0 : -1.0;
      facet_normal *= (sign*facet_measure/cell_volume);
      
      // Dofs of CR on the facet, local order
      std::vector<std::size_t> facet_dofs;
      CR1_dofmap->tabulate_facet_dofs(facet_dofs, local_facet_index);
      
      for (std::size_t j = 0 ; j < facet_dofs.size(); j++)
      {   
        columns.push_back(cr_dofs[facet_dofs[j]]);
        values.push_back(facet_normal[j]);
      }        
      local_facet_index += 1;
    }
    M.setrow(cell_dof, columns, values);
    columns.clear();
    values.clear();
  }
  M.apply("insert");
  //std::shared_ptr<GenericMatrix> Cp = MatMatMult(M, A);
  //return Cp;
}
Exemplo n.º 4
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");
}