diff --git a/python/py_dof_manager.cc b/python/py_dof_manager.cc index 074a3907b..6633335c7 100644 --- a/python/py_dof_manager.cc +++ b/python/py_dof_manager.cc @@ -1,218 +1,229 @@ /** * Copyright (©) 2021-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * This file is part of Akantu * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. */ /* -------------------------------------------------------------------------- */ #include "py_dof_manager.hh" #include "py_aka_array.hh" #include "py_akantu_pybind11_compatibility.hh" /* -------------------------------------------------------------------------- */ #include <dof_manager.hh> #include <non_linear_solver.hh> #include <solver_callback.hh> #include <time_step_solver.hh> /* -------------------------------------------------------------------------- */ #include <pybind11/operators.h> #include <pybind11/pybind11.h> #include <pybind11/stl.h> /* -------------------------------------------------------------------------- */ namespace py = pybind11; /* -------------------------------------------------------------------------- */ namespace akantu { namespace { class PySolverCallback : public SolverCallback { public: using SolverCallback::SolverCallback; /// get the type of matrix needed MatrixType getMatrixType(const ID & matrix_id) const override { // NOLINTNEXTLINE PYBIND11_OVERRIDE_PURE(MatrixType, SolverCallback, getMatrixType, matrix_id); } /// callback to assemble a Matrix void assembleMatrix(const ID & matrix_id) override { // NOLINTNEXTLINE PYBIND11_OVERRIDE_PURE(void, SolverCallback, assembleMatrix, matrix_id); } /// callback to assemble a lumped Matrix void assembleLumpedMatrix(const ID & matrix_id) override { // NOLINTNEXTLINE PYBIND11_OVERRIDE_PURE(void, SolverCallback, assembleLumpedMatrix, matrix_id); } /// callback to assemble the residual (rhs) void assembleResidual() override { // NOLINTNEXTLINE PYBIND11_OVERRIDE_PURE(void, SolverCallback, assembleResidual, ); } /// callback for the predictor (in case of dynamic simulation) void predictor() override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, SolverCallback, predictor, ); } /// callback for the corrector (in case of dynamic simulation) void corrector() override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, SolverCallback, corrector, ); } void beforeSolveStep() override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, SolverCallback, beforeSolveStep, ); } void afterSolveStep(bool converged) override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, SolverCallback, afterSolveStep, converged); } }; class PyInterceptSolverCallback : public InterceptSolverCallback { public: using InterceptSolverCallback::InterceptSolverCallback; MatrixType getMatrixType(const ID & matrix_id) const override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(MatrixType, InterceptSolverCallback, getMatrixType, matrix_id); } void assembleMatrix(const ID & matrix_id) override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, InterceptSolverCallback, assembleMatrix, matrix_id); } /// callback to assemble a lumped Matrix void assembleLumpedMatrix(const ID & matrix_id) override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, InterceptSolverCallback, assembleLumpedMatrix, matrix_id); } void assembleResidual() override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, InterceptSolverCallback, assembleResidual, ); } void predictor() override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, InterceptSolverCallback, predictor, ); } void corrector() override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, InterceptSolverCallback, corrector, ); } void beforeSolveStep() override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, InterceptSolverCallback, beforeSolveStep, ); } void afterSolveStep(bool converged) override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, InterceptSolverCallback, afterSolveStep, converged); } }; + class PyNonLinearSolver : public NonLinearSolver { + public: + using NonLinearSolver::NonLinearSolver; + + void solve(SolverCallback & callback) override { + // NOLINTNEXTLINE + PYBIND11_OVERRIDE(void, NonLinearSolver, solve, callback); + } + }; } // namespace /* -------------------------------------------------------------------------- */ void register_dof_manager(py::module & mod) { py::class_<DOFManager, std::shared_ptr<DOFManager>>(mod, "DOFManager") .def("getMatrix", &DOFManager::getMatrix, py::return_value_policy::reference) .def( "getNewMatrix", [](DOFManager & self, const std::string & name, const std::string & matrix_to_copy_id) -> decltype(auto) { return self.getNewMatrix(name, matrix_to_copy_id); }, py::return_value_policy::reference) .def( "getResidual", [](DOFManager & self) -> decltype(auto) { return self.getResidual(); }, py::return_value_policy::reference) .def("getArrayPerDOFs", &DOFManager::getArrayPerDOFs) .def( "hasMatrix", [](DOFManager & self, const ID & name) -> bool { return self.hasMatrix(name); }, py::arg("name")) .def("assembleToResidual", &DOFManager::assembleToResidual, py::arg("dof_id"), py::arg("array_to_assemble"), py::arg("scale_factor") = 1.) .def("assembleToLumpedMatrix", &DOFManager::assembleToLumpedMatrix, py::arg("dof_id"), py::arg("array_to_assemble"), py::arg("lumped_mtx"), py::arg("scale_factor") = 1.) .def("assemblePreassembledMatrix", &DOFManager::assemblePreassembledMatrix, py::arg("matrix_id"), py::arg("terms")) .def("zeroResidual", &DOFManager::zeroResidual); - py::class_<NonLinearSolver, Parsable>(mod, "NonLinearSolver") + py::class_<NonLinearSolver, Parsable, PyNonLinearSolver>(mod, + "NonLinearSolver") .def( "set", [](NonLinearSolver & self, const std::string & id, const Real & val) { if (id == "max_iterations") { self.set(id, int(val)); } else { self.set(id, val); } }) .def("set", [](NonLinearSolver & self, const std::string & id, - const SolveConvergenceCriteria & val) { self.set(id, val); }); + const SolveConvergenceCriteria & val) { self.set(id, val); }) + .def("solve", &NonLinearSolver::solve); py::class_<TimeStepSolver>(mod, "TimeStepSolver") .def("getIntegrationScheme", &TimeStepSolver::getIntegrationScheme); py::class_<SolverCallback, PySolverCallback>(mod, "SolverCallback") .def(py::init_alias<DOFManager &>()) .def("getMatrixType", &SolverCallback::getMatrixType) .def("assembleMatrix", &SolverCallback::assembleMatrix) .def("assembleLumpedMatrix", &SolverCallback::assembleLumpedMatrix) .def("assembleResidual", [](SolverCallback & self) { self.assembleResidual(); }) .def("predictor", &SolverCallback::predictor) .def("corrector", &SolverCallback::corrector) .def("beforeSolveStep", &SolverCallback::beforeSolveStep) .def("afterSolveStep", &SolverCallback::afterSolveStep) .def_property_readonly("dof_manager", &SolverCallback::getSCDOFManager, py::return_value_policy::reference); py::class_<InterceptSolverCallback, SolverCallback, PyInterceptSolverCallback>(mod, "InterceptSolverCallback") .def(py::init_alias<SolverCallback &>()); } } // namespace akantu diff --git a/src/common/aka_math.hh b/src/common/aka_math.hh index b95391d82..3858368d1 100644 --- a/src/common/aka_math.hh +++ b/src/common/aka_math.hh @@ -1,150 +1,150 @@ /** * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * This file is part of Akantu * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. */ /* -------------------------------------------------------------------------- */ #include "aka_types.hh" /* -------------------------------------------------------------------------- */ #include <utility> /* -------------------------------------------------------------------------- */ #ifndef AKANTU_AKA_MATH_H_ #define AKANTU_AKA_MATH_H_ namespace akantu { /* -------------------------------------------------------------------------- */ namespace AKANTU_EXPORT Math { /// tolerance for functions that need one extern Real tolerance; // NOLINT /* ------------------------------------------------------------------------ */ /* Geometry */ /* ------------------------------------------------------------------------ */ /// compute normal a normal to a vector template <class D1, std::enable_if_t<aka::is_vector_v<D1>> * = nullptr> inline Vector<Real> normal(const Eigen::MatrixBase<D1> & vec); template <class D1, aka::enable_if_t<not aka::is_vector_v<D1>> * = nullptr> inline Vector<Real> normal(const Eigen::MatrixBase<D1> & /*vec*/) { AKANTU_TO_IMPLEMENT(); } /// compute normal a normal to a vector template <class D1, class D2, std::enable_if_t<aka::are_vectors<D1, D2>::value> * = nullptr> inline Vector<Real, 3> normal(const Eigen::MatrixBase<D1> & vec1, const Eigen::MatrixBase<D2> & vec2); /// compute the tangents to an array of normal vectors void compute_tangents(const Array<Real> & normals, Array<Real> & tangents); /// radius of the in-circle of a triangle in 2d space template <class D1, class D2, class D3> static inline Real triangle_inradius(const Eigen::MatrixBase<D1> & coord1, const Eigen::MatrixBase<D2> & coord2, const Eigen::MatrixBase<D3> & coord3); /// radius of the in-circle of a tetrahedron template <class D1, class D2, class D3, class D4> static inline Real tetrahedron_inradius(const Eigen::MatrixBase<D1> & coord1, const Eigen::MatrixBase<D2> & coord2, const Eigen::MatrixBase<D3> & coord3, const Eigen::MatrixBase<D4> & coord4); /// volume of a tetrahedron template <class D1, class D2, class D3, class D4> static inline Real tetrahedron_volume(const Eigen::MatrixBase<D1> & coord1, const Eigen::MatrixBase<D2> & coord2, const Eigen::MatrixBase<D3> & coord3, const Eigen::MatrixBase<D4> & coord4); /// compute the barycenter of n points template <class D1, class D2> inline void barycenter(const Eigen::MatrixBase<D1> & coord, Eigen::MatrixBase<D2> & barycenter); /// test if two scalar are equal within a given tolerance inline bool are_float_equal(Real x, Real y); /// test if two vectors are equal within a given tolerance inline bool are_vector_equal(Int n, Real * x, Real * y); #ifdef isnan #error \ "You probably included <math.h> which is incompatible with aka_math please use\ <cmath> or add a \"#undef isnan\" before akantu includes" #endif /// test if a real is a NaN inline bool isnan(Real x); /// test if the line x and y intersects each other inline bool intersects(Real x_min, Real x_max, Real y_min, Real y_max); /// test if a is in the range [x_min, x_max] inline bool is_in_range(Real a, Real x_min, Real x_max); inline Real getTolerance() { return Math::tolerance; } inline void setTolerance(Real tol) { Math::tolerance = tol; } template <Int p, typename T> inline T pow(T x); template <class T1, class T2, std::enable_if_t<std::is_integral<T1>::value and std::is_integral<T2>::value> * = nullptr> inline Real kronecker(T1 i, T2 j) { return static_cast<Real>(i == j); } /* -------------------------------------------------------------------------- */ template <typename T> static inline constexpr T pow(T x, int p) { return p == 0 ? T(1) : (pow(x, p - 1) * x); } /// reduce all the values of an array, the summation is done in place and the /// array is modified - Real reduce(Array<Real> & array); + AKANTU_EXPORT Real reduce(Array<Real> & array); template <class T> class NewtonRaphson { public: NewtonRaphson(Real tolerance, Int max_iteration) : tolerance(tolerance), max_iteration(max_iteration) {} template <class Functor> T solve(const Functor & funct, const T & x_0); private: Real tolerance; Int max_iteration; }; template <class T> struct NewtonRaphsonFunctor { explicit NewtonRaphsonFunctor(const std::string & name) : name(name) {} virtual T f(const T & x) const = 0; virtual T f_prime(const T & x) const = 0; std::string name; }; } // namespace Math } // namespace akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "aka_math_tmpl.hh" #endif /* AKANTU_AKA_MATH_H_ */ diff --git a/src/model/common/dof_manager/dof_manager_default.cc b/src/model/common/dof_manager/dof_manager_default.cc index 231bb7dd7..965479386 100644 --- a/src/model/common/dof_manager/dof_manager_default.cc +++ b/src/model/common/dof_manager/dof_manager_default.cc @@ -1,471 +1,473 @@ /** * Copyright (©) 2015-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * This file is part of Akantu * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. */ /* -------------------------------------------------------------------------- */ #include "dof_manager_default.hh" #include "communicator.hh" #include "dof_synchronizer.hh" #include "element_group.hh" #include "non_linear_solver_default.hh" #include "periodic_node_synchronizer.hh" #include "solver_vector_default.hh" #include "solver_vector_distributed.hh" #include "sparse_matrix_aij.hh" #include "time_step_solver_default.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <memory> #include <numeric> #include <unordered_map> /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ DOFManagerDefault::DOFManagerDefault(const ID & id) : DOFManager(id), synchronizer(nullptr) { residual = std::make_unique<SolverVectorDefault>( *this, std::string(id + ":residual")); solution = std::make_unique<SolverVectorDefault>( *this, std::string(id + ":solution")); data_cache = std::make_unique<SolverVectorDefault>( *this, std::string(id + ":data_cache")); } /* -------------------------------------------------------------------------- */ DOFManagerDefault::DOFManagerDefault(Mesh & mesh, const ID & id) : DOFManager(mesh, id), synchronizer(nullptr) { if (this->mesh->isDistributed()) { this->synchronizer = std::make_unique<DOFSynchronizer>( *this, this->id + ":dof_synchronizer"); residual = std::make_unique<SolverVectorDistributed>( *this, std::string(id + ":residual")); solution = std::make_unique<SolverVectorDistributed>( *this, std::string(id + ":solution")); data_cache = std::make_unique<SolverVectorDistributed>( *this, std::string(id + ":data_cache")); } else { residual = std::make_unique<SolverVectorDefault>( *this, std::string(id + ":residual")); solution = std::make_unique<SolverVectorDefault>( *this, std::string(id + ":solution")); data_cache = std::make_unique<SolverVectorDefault>( *this, std::string(id + ":data_cache")); } } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::makeConsistentForPeriodicity(const ID & dof_id, SolverVector & array) { auto & dof_data = this->getDOFDataTyped<DOFDataDefault>(dof_id); if (dof_data.support_type != _dst_nodal) { return; } if (not mesh->isPeriodic()) { return; } this->mesh->getPeriodicNodeSynchronizer() .reduceSynchronizeWithPBCSlaves<AddOperation>( aka::as_type<SolverVectorDefault>(array).getVector()); } /* -------------------------------------------------------------------------- */ template <typename T> void DOFManagerDefault::assembleToGlobalArray( const ID & dof_id, const Array<T> & array_to_assemble, Array<T> & global_array, T scale_factor) { AKANTU_DEBUG_IN(); auto & dof_data = this->getDOFDataTyped<DOFDataDefault>(dof_id); AKANTU_DEBUG_ASSERT(dof_data.local_equation_number.size() == array_to_assemble.size() * array_to_assemble.getNbComponent(), "The array to assemble does not have a correct size." << " (" << array_to_assemble.getID() << ")"); if (dof_data.support_type == _dst_nodal and mesh->isPeriodic()) { for (auto && data : zip(dof_data.local_equation_number, dof_data.associated_nodes, make_view(array_to_assemble))) { auto && equ_num = std::get<0>(data); // auto && node = std::get<1>(data); auto && arr = std::get<2>(data); // Guillaume to Nico: // This filter of periodic slave should not be. // Indeed you want to get the contribution even // from periodic slaves and cumulate to the right // equation number. global_array(equ_num) += scale_factor * (arr); // scale_factor * (arr) * (not this->mesh->isPeriodicSlave(node)); } } else { for (auto && data : zip(dof_data.local_equation_number, make_view(array_to_assemble))) { auto && equ_num = std::get<0>(data); auto && arr = std::get<1>(data); global_array(equ_num) += scale_factor * (arr); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleToGlobalArray( const ID & dof_id, const Array<Real> & array_to_assemble, SolverVector & global_array_v, Real scale_factor) { assembleToGlobalArray( dof_id, array_to_assemble, aka::as_type<SolverVectorDefault>(global_array_v).getVector(), scale_factor); } /* -------------------------------------------------------------------------- */ DOFManagerDefault::DOFDataDefault::DOFDataDefault(const ID & dof_id) : DOFData(dof_id) {} /* -------------------------------------------------------------------------- */ auto DOFManagerDefault::getNewDOFData(const ID & dof_id) -> std::unique_ptr<DOFData> { return std::make_unique<DOFDataDefault>(dof_id); } /* -------------------------------------------------------------------------- */ std::tuple<Int, Int, Int> DOFManagerDefault::registerDOFsInternal(const ID & dof_id, Array<Real> & dofs_array) { auto ret = DOFManager::registerDOFsInternal(dof_id, dofs_array); // update the synchronizer if needed if (this->synchronizer) { this->synchronizer->registerDOFs(dof_id); } return ret; } /* -------------------------------------------------------------------------- */ SparseMatrix & DOFManagerDefault::getNewMatrix(const ID & id, const MatrixType & matrix_type) { return this->registerSparseMatrix<SparseMatrixAIJ>(*this, id, matrix_type); } /* -------------------------------------------------------------------------- */ SparseMatrix & DOFManagerDefault::getNewMatrix(const ID & id, const ID & matrix_to_copy_id) { return this->registerSparseMatrix<SparseMatrixAIJ>(id, matrix_to_copy_id); } /* -------------------------------------------------------------------------- */ SolverVector & DOFManagerDefault::getNewLumpedMatrix(const ID & id) { return this->registerLumpedMatrix<SolverVectorDefault>(*this, id); } /* -------------------------------------------------------------------------- */ SparseMatrixAIJ & DOFManagerDefault::getMatrix(const ID & id) { auto & matrix = DOFManager::getMatrix(id); return aka::as_type<SparseMatrixAIJ>(matrix); } /* -------------------------------------------------------------------------- */ NonLinearSolver & DOFManagerDefault::getNewNonLinearSolver(const ID & id, const NonLinearSolverType & type) { switch (type) { #if defined(AKANTU_USE_MUMPS) case NonLinearSolverType::_newton_raphson: /* FALLTHRU */ /* [[fallthrough]]; un-comment when compiler will get it */ case NonLinearSolverType::_newton_raphson_contact: case NonLinearSolverType::_newton_raphson_modified: { return this->registerNonLinearSolver<NonLinearSolverNewtonRaphson>( *this, id, type); } case NonLinearSolverType::_linear: { return this->registerNonLinearSolver<NonLinearSolverLinear>(*this, id, type); } #endif case NonLinearSolverType::_lumped: { return this->registerNonLinearSolver<NonLinearSolverLumped>(*this, id, type); } default: AKANTU_EXCEPTION("The asked type of non linear solver is not supported by " "this dof manager"); } } /* -------------------------------------------------------------------------- */ TimeStepSolver & DOFManagerDefault::getNewTimeStepSolver( const ID & id, const TimeStepSolverType & type, NonLinearSolver & non_linear_solver, SolverCallback & solver_callback) { return this->registerTimeStepSolver<TimeStepSolverDefault>( *this, id, type, non_linear_solver, solver_callback); } /* -------------------------------------------------------------------------- */ template <typename T> void DOFManagerDefault::getArrayPerDOFs(const ID & dof_id, const Array<T> & global_array, Array<T> & local_array) const { AKANTU_DEBUG_IN(); const auto & equation_number = this->getLocalEquationsNumbers(dof_id); auto nb_degree_of_freedoms = equation_number.size(); local_array.resize(nb_degree_of_freedoms / local_array.getNbComponent()); for (auto data : zip(equation_number, make_view(local_array))) { std::get<1>(data) = global_array(std::get<0>(data)); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::getArrayPerDOFs(const ID & dof_id, const SolverVector & global_array, Array<Real> & local_array) { getArrayPerDOFs(dof_id, aka::as_type<SolverVectorDefault>(global_array).getVector(), local_array); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleLumpedMatMulVectToResidual( const ID & dof_id, const ID & A_id, const Array<Real> & x, Real scale_factor) { const auto & A = aka::as_type<SolverVectorArray>(this->getLumpedMatrix(A_id)).getVector(); auto & cache = aka::as_type<SolverVectorArray>(*this->data_cache); cache.zero(); this->assembleToGlobalArray(dof_id, x, cache.getVector(), scale_factor); for (auto && data : zip(make_view(A), make_view(cache.getVector()), make_view(this->getResidualArray()))) { const auto & A = std::get<0>(data); const auto & x = std::get<1>(data); auto & r = std::get<2>(data); r += A * x; } } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleElementalMatricesToMatrix( const ID & matrix_id, const ID & dof_id, const Array<Real> & elementary_mat, ElementType type, GhostType ghost_type, const MatrixType & elemental_matrix_type, const Array<Int> & filter_elements) { this->addToProfile(matrix_id, dof_id, type, ghost_type); auto & A = getMatrix(matrix_id); DOFManager::assembleElementalMatricesToMatrix_( A, dof_id, elementary_mat, type, ghost_type, elemental_matrix_type, filter_elements); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assemblePreassembledMatrix( const ID & matrix_id, const TermsToAssemble & terms) { auto & A = getMatrix(matrix_id); DOFManager::assemblePreassembledMatrix_(A, terms); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::assembleMatMulVectToArray(const ID & dof_id, const ID & A_id, const Array<Real> & x, Array<Real> & array, Real scale_factor) { if (mesh->isDistributed()) { DOFManager::assembleMatMulVectToArray_<SolverVectorDistributed>( dof_id, A_id, x, array, scale_factor); } else { DOFManager::assembleMatMulVectToArray_<SolverVectorDefault>( dof_id, A_id, x, array, scale_factor); } } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::addToProfile(const ID & matrix_id, const ID & dof_id, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); const auto & dof_data = this->getDOFData(dof_id); if (dof_data.support_type != _dst_nodal) { return; } auto mat_dof = std::make_pair(matrix_id, dof_id); auto type_pair = std::make_pair(type, ghost_type); auto prof_it = this->matrix_profiled_dofs.find(mat_dof); if (prof_it != this->matrix_profiled_dofs.end() && std::find(prof_it->second.begin(), prof_it->second.end(), type_pair) != prof_it->second.end()) { return; } auto nb_degree_of_freedom_per_node = dof_data.dof->getNbComponent(); const auto & equation_number = this->getLocalEquationsNumbers(dof_id); auto & A = this->getMatrix(matrix_id); A.resize(system_size); auto size = A.size(); auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const auto & connectivity = this->mesh->getConnectivity(type, ghost_type); auto cbegin = connectivity.begin(nb_nodes_per_element); auto cit = cbegin; auto nb_elements = connectivity.size(); Int * ge_it = nullptr; if (dof_data.group_support != "__mesh__") { const auto & group_elements = this->mesh->getElementGroup(dof_data.group_support) .getElements(type, ghost_type); ge_it = group_elements.data(); nb_elements = group_elements.size(); } auto size_mat = nb_nodes_per_element * nb_degree_of_freedom_per_node; Vector<Int> element_eq_nb(size_mat); for (Int e = 0; e < nb_elements; ++e) { if (ge_it != nullptr) { cit = cbegin + *ge_it; } this->extractElementEquationNumber( equation_number, *cit, nb_degree_of_freedom_per_node, element_eq_nb); std::transform( element_eq_nb.begin(), element_eq_nb.end(), element_eq_nb.begin(), [&](auto & local) { return this->localToGlobalEquationNumber(local); }); if (ge_it != nullptr) { ++ge_it; } else { ++cit; } for (Int i = 0; i < size_mat; ++i) { auto c_irn = element_eq_nb(i); if (c_irn < size) { for (Int j = 0; j < size_mat; ++j) { auto c_jcn = element_eq_nb(j); if (c_jcn < size) { A.add(c_irn, c_jcn); } } } } } this->matrix_profiled_dofs[mat_dof].push_back(type_pair); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Array<Real> & DOFManagerDefault::getSolutionArray() { return dynamic_cast<SolverVectorDefault *>(this->solution.get())->getVector(); } /* -------------------------------------------------------------------------- */ const Array<Real> & DOFManagerDefault::getResidualArray() const { return dynamic_cast<SolverVectorDefault *>(this->residual.get())->getVector(); } /* -------------------------------------------------------------------------- */ Array<Real> & DOFManagerDefault::getResidualArray() { return dynamic_cast<SolverVectorDefault *>(this->residual.get())->getVector(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::onNodesAdded(const Array<Idx> & nodes_list, const NewNodesEvent & event) { DOFManager::onNodesAdded(nodes_list, event); if (this->synchronizer) { this->synchronizer->onNodesAdded(nodes_list); } } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::resizeGlobalArrays() { DOFManager::resizeGlobalArrays(); this->global_blocked_dofs.resize(this->local_system_size, 1); this->previous_global_blocked_dofs.resize(this->local_system_size, 1); matrix_profiled_dofs.clear(); } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::updateGlobalBlockedDofs() { DOFManager::updateGlobalBlockedDofs(); if (this->global_blocked_dofs_release == this->previous_global_blocked_dofs_release) { return; } global_blocked_dofs_uint.resize(local_system_size); global_blocked_dofs_uint.set(false); for (const auto & dof : global_blocked_dofs) { global_blocked_dofs_uint[dof] = true; } } /* -------------------------------------------------------------------------- */ Array<bool> & DOFManagerDefault::getBlockedDOFs() { return global_blocked_dofs_uint; } /* -------------------------------------------------------------------------- */ const Array<bool> & DOFManagerDefault::getBlockedDOFs() const { return global_blocked_dofs_uint; } /* -------------------------------------------------------------------------- */ -static bool dof_manager_is_registered = +const bool dof_manager_is_registered [[maybe_unused]] = DOFManagerFactory::getInstance().registerAllocator( "default", [](Mesh & mesh, const ID & id) -> std::unique_ptr<DOFManager> { return std::make_unique<DOFManagerDefault>(mesh, id); }); -static bool dof_manager_is_registered_mumps = +#if defined(AKANTU_USE_MUMPS) +const bool dof_manager_is_registered_mumps [[maybe_unused]] = DOFManagerFactory::getInstance().registerAllocator( "mumps", [](Mesh & mesh, const ID & id) -> std::unique_ptr<DOFManager> { return std::make_unique<DOFManagerDefault>(mesh, id); }); +#endif } // namespace akantu diff --git a/src/model/common/non_linear_solver/non_linear_solver.hh b/src/model/common/non_linear_solver/non_linear_solver.hh index 8c7c5da19..10bb1fd1d 100644 --- a/src/model/common/non_linear_solver/non_linear_solver.hh +++ b/src/model/common/non_linear_solver/non_linear_solver.hh @@ -1,104 +1,104 @@ /** * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * This file is part of Akantu * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ #include <set> /* -------------------------------------------------------------------------- */ #ifndef AKANTU_NON_LINEAR_SOLVER_HH_ #define AKANTU_NON_LINEAR_SOLVER_HH_ namespace akantu { class DOFManager; class SolverCallback; } // namespace akantu namespace akantu { -class NonLinearSolver : public Parsable { +class AKANTU_EXPORT NonLinearSolver : public Parsable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NonLinearSolver(DOFManager & dof_manager, const NonLinearSolverType & non_linear_solver_type, const ID & id = "non_linear_solver"); ~NonLinearSolver() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// solve the system described by the jacobian matrix, and rhs contained in /// the dof manager virtual void solve(SolverCallback & callback) = 0; /// intercept the call to set for options template <typename T> void set(const ID & param, T && t) { if (has_internal_set_param) { set_param(param, std::to_string(t)); } else { ParameterRegistry::set(param, t); } } protected: void checkIfTypeIsSupported(); void assembleResidual(SolverCallback & callback); /// internal set param for solvers that should intercept the parameters virtual void set_param(const ID & /*param*/, const std::string & /*value*/) {} /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: ID id; DOFManager & _dof_manager; /// type of non linear solver NonLinearSolverType non_linear_solver_type; /// list of supported non linear solver types std::set<NonLinearSolverType> supported_type; /// specifies if the set param should be redirected bool has_internal_set_param{false}; }; namespace debug { class NLSNotConvergedException : public Exception { public: NLSNotConvergedException(Real threshold, Int niter, Real error) : Exception("The non linear solver did not converge."), threshold(threshold), niter(niter), error(error) {} Real threshold; Int niter; Real error; }; } // namespace debug } // namespace akantu #endif /* AKANTU_NON_LINEAR_SOLVER_HH_ */