void VectorMatrixAssembler::preAssemble( const std::size_t mesh_item_id, LocalAssemblerInterface& local_assembler, const NumLib::LocalToGlobalIndexMap& dof_table, const double t, const GlobalVector& x) { auto const indices = NumLib::getIndices(mesh_item_id, dof_table); auto const local_x = x.get(indices); local_assembler.preAssemble(t, local_x); }
void VectorMatrixAssembler::assemble( const std::size_t mesh_item_id, LocalAssemblerInterface& local_assembler, std::vector<std::reference_wrapper<NumLib::LocalToGlobalIndexMap>> const& dof_tables, const double t, const GlobalVector& x, GlobalMatrix& M, GlobalMatrix& K, GlobalVector& b, CoupledSolutionsForStaggeredScheme const* const cpl_xs) { std::vector<std::vector<GlobalIndexType>> indices_of_processes; indices_of_processes.reserve(dof_tables.size()); for (std::size_t i = 0; i < dof_tables.size(); i++) { indices_of_processes.emplace_back( NumLib::getIndices(mesh_item_id, dof_tables[i].get())); } auto const& indices = (cpl_xs == nullptr) ? indices_of_processes[0] : indices_of_processes[cpl_xs->process_id]; _local_M_data.clear(); _local_K_data.clear(); _local_b_data.clear(); if (cpl_xs == nullptr) { auto const local_x = x.get(indices); local_assembler.assemble(t, local_x, _local_M_data, _local_K_data, _local_b_data); } else { auto local_coupled_xs0 = getPreviousLocalSolutions(*cpl_xs, indices_of_processes); auto local_coupled_xs = getCurrentLocalSolutions(*cpl_xs, indices_of_processes); ProcessLib::LocalCoupledSolutions local_coupled_solutions( cpl_xs->dt, cpl_xs->process_id, std::move(local_coupled_xs0), std::move(local_coupled_xs)); local_assembler.assembleForStaggeredScheme(t, _local_M_data, _local_K_data, _local_b_data, local_coupled_solutions); } auto const num_r_c = indices.size(); auto const r_c_indices = NumLib::LocalToGlobalIndexMap::RowColumnIndices(indices, indices); if (!_local_M_data.empty()) { auto const local_M = MathLib::toMatrix(_local_M_data, num_r_c, num_r_c); M.add(r_c_indices, local_M); } if (!_local_K_data.empty()) { auto const local_K = MathLib::toMatrix(_local_K_data, num_r_c, num_r_c); K.add(r_c_indices, local_K); } if (!_local_b_data.empty()) { assert(_local_b_data.size() == num_r_c); b.add(indices, _local_b_data); } }
void CentralDifferencesJacobianAssembler::assembleWithJacobian( LocalAssemblerInterface& local_assembler, const double t, const std::vector<double>& local_x_data, const std::vector<double>& local_xdot_data, const double dxdot_dx, const double dx_dx, std::vector<double>& local_M_data, std::vector<double>& local_K_data, std::vector<double>& local_b_data, std::vector<double>& local_Jac_data) { // TODO do not check in every call. if (local_x_data.size() % _absolute_epsilons.size() != 0) { OGS_FATAL( "The number of specified epsilons (%u) and the number of local " "d.o.f.s (%u) do not match, i.e., the latter is not divisable by " "the former.", _absolute_epsilons.size(), local_x_data.size()); } auto const num_r_c = static_cast<Eigen::MatrixXd::Index>(local_x_data.size()); auto const local_x = MathLib::toVector<Eigen::VectorXd>(local_x_data, num_r_c); auto const local_xdot = MathLib::toVector<Eigen::VectorXd>(local_xdot_data, num_r_c); auto local_Jac = MathLib::createZeroedMatrix(local_Jac_data, num_r_c, num_r_c); _local_x_perturbed_data = local_x_data; auto const num_dofs_per_component = local_x_data.size() / _absolute_epsilons.size(); // Residual res := M xdot + K x - b // Computing Jac := dres/dx // = M dxdot/dx + dM/dx xdot + K dx/dx + dK/dx x - db/dx // (Note: dM/dx and dK/dx actually have the second and // third index transposed.) // The loop computes the dM/dx, dK/dx and db/dx terms, the rest is computed // afterwards. for (Eigen::MatrixXd::Index i = 0; i < num_r_c; ++i) { // assume that local_x_data is ordered by component. auto const component = i / num_dofs_per_component; auto const eps = _absolute_epsilons[component]; _local_x_perturbed_data[i] += eps; local_assembler.assemble(t, _local_x_perturbed_data, local_M_data, local_K_data, local_b_data); _local_x_perturbed_data[i] = local_x_data[i] - eps; local_assembler.assemble(t, _local_x_perturbed_data, _local_M_data, _local_K_data, _local_b_data); _local_x_perturbed_data[i] = local_x_data[i]; if (!local_M_data.empty()) { auto const local_M_p = MathLib::toMatrix(local_M_data, num_r_c, num_r_c); auto const local_M_m = MathLib::toMatrix(_local_M_data, num_r_c, num_r_c); local_Jac.col(i).noalias() += // dM/dxi * x_dot (local_M_p - local_M_m) * local_xdot / (2.0 * eps); local_M_data.clear(); _local_M_data.clear(); } if (!local_K_data.empty()) { auto const local_K_p = MathLib::toMatrix(local_K_data, num_r_c, num_r_c); auto const local_K_m = MathLib::toMatrix(_local_K_data, num_r_c, num_r_c); local_Jac.col(i).noalias() += // dK/dxi * x (local_K_p - local_K_m) * local_x / (2.0 * eps); local_K_data.clear(); _local_K_data.clear(); } if (!local_b_data.empty()) { auto const local_b_p = MathLib::toVector<Eigen::VectorXd>(local_b_data, num_r_c); auto const local_b_m = MathLib::toVector<Eigen::VectorXd>(_local_b_data, num_r_c); local_Jac.col(i).noalias() -= // db/dxi (local_b_p - local_b_m) / (2.0 * eps); local_b_data.clear(); _local_b_data.clear(); } } // Assemble with unperturbed local x. local_assembler.assemble(t, local_x_data, local_M_data, local_K_data, local_b_data); // Compute remaining terms of the Jacobian. if (dxdot_dx != 0.0 && !local_M_data.empty()) { auto local_M = MathLib::toMatrix(local_M_data, num_r_c, num_r_c); local_Jac.noalias() += local_M * dxdot_dx; } if (dx_dx != 0.0 && !local_K_data.empty()) { auto local_K = MathLib::toMatrix(local_K_data, num_r_c, num_r_c); local_Jac.noalias() += local_K * dx_dx; } }