//----------------------------------------------------------------------------- void AssemblerBase::check(const Form& a) { dolfin_assert(a.ufc_form()); // Check the form a.check(); // Extract mesh and coefficients const Mesh& mesh = a.mesh(); const std::vector<std::shared_ptr<const GenericFunction>> coefficients = a.coefficients(); // Check that we get the correct number of coefficients if (coefficients.size() != a.num_coefficients()) { dolfin_error("AssemblerBase.cpp", "assemble form", "Incorrect number of coefficients (got %d but expecting %d)", coefficients.size(), a.num_coefficients()); } // Check that all coefficients have valid value dimensions for (std::size_t i = 0; i < coefficients.size(); ++i) { if (!coefficients[i]) { dolfin_error("AssemblerBase.cpp", "assemble form", "Coefficient number %d (\"%s\") has not been set", i, a.coefficient_name(i).c_str()); } // unique_ptr deletes its object when it exits its scope std::unique_ptr<ufc::finite_element> fe(a.ufc_form()->create_finite_element(i + a.rank())); // Checks out-commented since they only work for Functions, not // Expressions const std::size_t r = coefficients[i]->value_rank(); const std::size_t fe_r = fe->value_rank(); if (fe_r != r) { dolfin_error("AssemblerBase.cpp", "assemble form", "Invalid value rank for coefficient %d (got %d but expecting %d). \ You might have forgotten to specify the value rank correctly in an Expression subclass", i, r, fe_r); } for (std::size_t j = 0; j < r; ++j) { const std::size_t dim = coefficients[i]->value_dimension(j); const std::size_t fe_dim = fe->value_dimension(j); if (dim != fe_dim) { dolfin_error("AssemblerBase.cpp", "assemble form", "Invalid value dimension %d for coefficient %d (got %d but expecting %d). \ You might have forgotten to specify the value dimension correctly in an Expression subclass", j, i, dim, fe_dim); } }
//---------------------------------------------------------------------------- void Assembler::assemble(GenericTensor& A, const Form& a) { // All assembler functions above end up calling this function, which // in turn calls the assembler functions below to assemble over // cells, exterior and interior facets. // Check whether we should call the multi-core assembler #ifdef HAS_OPENMP const std::size_t num_threads = parameters["num_threads"]; if (num_threads > 0) { OpenMpAssembler assembler; assembler.add_values = add_values; assembler.finalize_tensor = finalize_tensor; assembler.keep_diagonal = keep_diagonal; assembler.assemble(A, a); return; } #endif // Get cell domains std::shared_ptr<const MeshFunction<std::size_t>> cell_domains = a.cell_domains(); // Get exterior facet domains std::shared_ptr<const MeshFunction<std::size_t>> exterior_facet_domains = a.exterior_facet_domains(); // Get interior facet domains std::shared_ptr<const MeshFunction<std::size_t>> interior_facet_domains = a.interior_facet_domains(); // Get vertex domains std::shared_ptr<const MeshFunction<std::size_t>> vertex_domains = a.vertex_domains(); // Check form AssemblerBase::check(a); // Create data structure for local assembly data UFC ufc(a); // Update off-process coefficients const std::vector<std::shared_ptr<const GenericFunction>> coefficients = a.coefficients(); // Initialize global tensor init_global_tensor(A, a); // Assemble over cells assemble_cells(A, a, ufc, cell_domains, NULL); // Assemble over exterior facets assemble_exterior_facets(A, a, ufc, exterior_facet_domains, NULL); // Assemble over interior facets assemble_interior_facets(A, a, ufc, interior_facet_domains, cell_domains, NULL); // Assemble over vertices assemble_vertices(A, a, ufc, vertex_domains); // Finalize assembly of global tensor if (finalize_tensor) A.apply("add"); }