//----------------------------------------------------------------------------- void DofMap::set_x(GenericVector& x, double value, std::size_t component, const Mesh& mesh) const { UFCCell ufc_cell(mesh); std::vector<double> x_values; boost::multi_array<double, 2> coordinates; for (CellIterator cell(mesh); !cell.end(); ++cell) { // Update UFC cell ufc_cell.update(*cell); // Get local-to-global map const std::vector<dolfin::la_index>& dofs = cell_dofs(cell->index()); // Tabulate dof coordinates tabulate_coordinates(coordinates, ufc_cell); dolfin_assert(coordinates.shape()[0] == dofs.size()); dolfin_assert(component < coordinates.shape()[1]); // Copy coordinate (it may be possible to avoid this) x_values.resize(dofs.size()); for (std::size_t i = 0; i < coordinates.shape()[0]; ++i) x_values[i] = value*coordinates[i][component]; // Set x[component] values in vector x.set(x_values.data(), dofs.size(), dofs.data()); } }
//----------------------------------------------------------------------------- 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"); }
//----------------------------------------------------------------------------- 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(); }
//---------------------------------------------------------------------------- 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"); }
//----------------------------------------------------------------------------- std::size_t MUMPSLUSolver::solve(GenericVector& x, const GenericVector& b) { assert(_A); DMUMPS_STRUC_C data; data.comm_fortran = -987654; // Initialise data.job = -1; // Host participates in solve data.par = 1; // Output related paramters //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 postitve 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(_A->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 assert(_A->size(0) == _A->size(1)); data.n = _A->size(0); if (!_A->base_one()) error("MUMPS requires a CoordinateMatrix with Fortran-style base 1 indexing."); // Get matrix coordindate and value data const std::vector<std::size_t>& rows = _A->rows(); const std::vector<std::size_t>& cols = _A->columns(); const std::vector<double>& vals = _A->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[0]); // Analyse and factorize data.job = 4; dmumps_c(&data); if (data.INFOG(1) < 0) error("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[0]; // 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) error("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 x.set(x_local_vals.data(), x_local_indices.size(), x_local_indices.data()); x.apply("insert"); // Clean up data.job = -2; dmumps_c(&data); return 1; }