diff --git a/python/py_dof_manager.cc b/python/py_dof_manager.cc index 31bcdcf75..1a073da25 100644 --- a/python/py_dof_manager.cc +++ b/python/py_dof_manager.cc @@ -1,215 +1,216 @@ /* * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * 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 . */ /* -------------------------------------------------------------------------- */ #include "py_dof_manager.hh" #include "py_aka_array.hh" #include "py_akantu_pybind11_compatibility.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ 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); } }; } // namespace /* -------------------------------------------------------------------------- */ void register_dof_manager(py::module & mod) { py::class_>(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")); + py::arg("terms")) + .def("zeroResidual", &DOFManager::zeroResidual); py::class_(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); }); py::class_(mod, "TimeStepSolver") .def("getIntegrationScheme", &TimeStepSolver::getIntegrationScheme); py::class_(mod, "SolverCallback") .def(py::init_alias()) .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_(mod, "InterceptSolverCallback") .def(py::init_alias()); } } // namespace akantu diff --git a/python/py_solver.cc b/python/py_solver.cc index bbcd931c3..d5e20670d 100644 --- a/python/py_solver.cc +++ b/python/py_solver.cc @@ -1,113 +1,119 @@ /** * @file py_solver.cc * * @author Nicolas Richart * * @date creation: Tue Sep 29 2020 * @date last modification: Sat Mar 06 2021 * * @brief pybind11 interface to Solver and SparseMatrix * * * @section LICENSE * * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * 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 . * */ /* -------------------------------------------------------------------------- */ #include "py_solver.hh" #include "py_aka_array.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ namespace py = pybind11; /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void register_solvers(py::module & mod) { py::class_(mod, "SparseMatrix") .def("getMatrixType", &SparseMatrix::getMatrixType) .def("size", &SparseMatrix::size) .def("zero", &SparseMatrix::zero) .def("saveProfile", &SparseMatrix::saveProfile) .def("saveMatrix", &SparseMatrix::saveMatrix) .def( "add", [](SparseMatrix & self, UInt i, UInt j) { self.add(i, j); }, "Add entry in the profile") .def( "add", [](SparseMatrix & self, UInt i, UInt j, Real value) { self.add(i, j, value); }, "Add the value to the matrix") .def( "add", [](SparseMatrix & self, SparseMatrix & A, Real alpha) { self.add(A, alpha); }, "Add a matrix to the matrix", py::arg("A"), py::arg("alpha") = 1.) + + .def("isFinite", &SparseMatrix::isFinite) + + .def("getRelease", + [](const SparseMatrix & self) -> UInt { return self.getRelease(); }) .def("__call__", [](const SparseMatrix & self, UInt i, UInt j) { return self(i, j); }) .def("getRelease", &SparseMatrix::getRelease); py::class_(mod, "SparseMatrixAIJ") .def("getIRN", &SparseMatrixAIJ::getIRN) .def("getJCN", &SparseMatrixAIJ::getJCN) .def("getA", &SparseMatrixAIJ::getA); py::class_(mod, "SolverVector") - .def("getValues", - [](SolverVector& self) -> decltype(auto) { - return static_cast& >(self); - }, - py::return_value_policy::reference_internal, - "Transform this into a vector, Is not copied.") - .def("isDistributed", [](const SolverVector& self) { return self.isDistributed(); }) - ; + .def( + "getValues", + [](SolverVector & self) -> decltype(auto) { + return static_cast &>(self); + }, + py::return_value_policy::reference_internal, + "Transform this into a vector, Is not copied.") + .def("isDistributed", + [](const SolverVector & self) { return self.isDistributed(); }); py::class_(mod, "TermToAssemble") .def(py::init()) .def(py::self += Real()) .def_property_readonly("i", &TermsToAssemble::TermToAssemble::i) .def_property_readonly("j", &TermsToAssemble::TermToAssemble::j); py::class_(mod, "TermsToAssemble") .def(py::init()) .def("getDOFIdM", &TermsToAssemble::getDOFIdM) .def("getDOFIdN", &TermsToAssemble::getDOFIdN) .def( "__call__", [](TermsToAssemble & self, UInt i, UInt j, Real val) { auto & term = self(i, j); term = val; return term; }, py::arg("i"), py::arg("j"), py::arg("val") = 0., py::return_value_policy::reference); } } // namespace akantu diff --git a/python/py_structural_mechanics_model.cc b/python/py_structural_mechanics_model.cc index a80b6a529..366953881 100644 --- a/python/py_structural_mechanics_model.cc +++ b/python/py_structural_mechanics_model.cc @@ -1,162 +1,179 @@ /** * @file py_structural_mechanics_model.cc * * @author Philip Mueller * @author Mohit Pundir * @author Nicolas Richart * * @date creation: Wed Feb 03 2021 * @date last modification: Thu Apr 01 2021 * * @brief pybind11 interface to StructuralMechanicsModel * * * @section LICENSE * * Copyright (©) 2018-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * 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 . * */ /* -------------------------------------------------------------------------- */ #include "py_aka_array.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ namespace py = pybind11; /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ #define def_deprecated(func_name, mesg) \ def(func_name, [](py::args, py::kwargs) { AKANTU_ERROR(mesg); }) #define def_function_nocopy(func_name) \ def( \ #func_name, \ [](StructuralMechanicsModel & self) -> decltype(auto) { \ return self.func_name(); \ }, \ py::return_value_policy::reference) #define def_function_(func_name) \ def(#func_name, [](StructuralMechanicsModel & self) -> decltype(auto) { \ return self.func_name(); \ }) #define def_plainmember(M) def_readwrite(#M, &StructuralMaterial::M) /* -------------------------------------------------------------------------- */ void register_structural_mechanics_model(pybind11::module & mod) { /* First we have to register the material class * The wrapper aims to mimic the behaviour of the real material. */ py::class_(mod, "StructuralMaterial") .def(py::init<>()) .def(py::init()) .def_plainmember(E) .def_plainmember(A) .def_plainmember(I) .def_plainmember(Iz) .def_plainmember(Iy) .def_plainmember(GJ) .def_plainmember(rho) .def_plainmember(t) .def_plainmember(nu); /* Now we create the structural model wrapper * Note that this is basically a port from the solid mechanic part. */ py::class_(mod, "StructuralMechanicsModel") .def(py::init(), py::arg("mesh"), py::arg("spatial_dimension") = _all_dimensions, py::arg("id") = "structural_mechanics_model") .def( "initFull", [](StructuralMechanicsModel & self, const AnalysisMethod & analysis_method) -> void { self.initFull(_analysis_method = analysis_method); }, py::arg("_analysis_method")) .def("initFull", [](StructuralMechanicsModel & self) -> void { self.initFull(); }) .def_function_nocopy(getExternalForce) .def_function_nocopy(getDisplacement) .def_function_nocopy(getInternalForce) .def_function_nocopy(getVelocity) .def_function_nocopy(getAcceleration) .def_function_nocopy(getInternalForce) .def_function_nocopy(getBlockedDOFs) .def_function_nocopy(getMesh) .def("setTimeStep", &StructuralMechanicsModel::setTimeStep, py::arg("time_step"), py::arg("solver_id") = "") .def( "getElementMaterial", [](StructuralMechanicsModel & self, const ElementType & type, GhostType ghost_type) -> decltype(auto) { return self.getElementMaterial(type, ghost_type); }, "This function returns the map that maps elements to materials.", py::arg("type"), py::arg("ghost_type") = _not_ghost, py::return_value_policy::reference) .def( "getMaterialByElement", [](StructuralMechanicsModel & self, Element element) -> decltype(auto) { return self.getMaterialByElement(element); }, "This function returns the `StructuralMaterial` instance that is " "associated with element `element`.", py::arg("element"), py::return_value_policy::reference) .def( "addMaterial", [](StructuralMechanicsModel & self, StructuralMaterial & mat, const ID & name) -> UInt { return self.addMaterial(mat, name); }, "This function adds the `StructuralMaterial` `mat` to `self`." " The function returns the ID of the new material.", py::arg("mat"), py::arg("name") = "") .def( "getMaterial", - [](StructuralMechanicsModel & self, UInt material_index) - -> decltype(auto) { return self.getMaterial(material_index); }, + [](const StructuralMechanicsModel & self, + UInt material_index) -> StructuralMaterial { + return self.getMaterial(material_index); + }, "This function returns the `i`th material of `self`." - " Note a reference is returned which allows to modify the material " - "inside `self`.", - py::arg("i"), py::return_value_policy::reference) + " The function returns a copy of the material.", + py::arg("material_index"), py::return_value_policy::copy) .def( "getMaterial", - [](StructuralMechanicsModel & self, const ID & name) - -> decltype(auto) { return self.getMaterial(name); }, - "This function returns the material with name `i` of `self`." - " Note a reference is returned which allows to modify the material " - "inside `self`.", - py::arg("i"), py::return_value_policy::reference) + [](const StructuralMechanicsModel & self, const ID & name) + -> StructuralMaterial { return self.getMaterial(name); }, + "This function returns the `i`th material of `self`." + " The function returns a copy of the material.", + py::arg("material_index"), py::return_value_policy::copy) .def( "getNbMaterials", [](StructuralMechanicsModel & self) { return self.getNbMaterials(); }, "Returns the number of different materials inside `self`.") + .def("getKineticEnergy", &StructuralMechanicsModel::getKineticEnergy, "Compute kinetic energy") .def("getPotentialEnergy", &StructuralMechanicsModel::getPotentialEnergy, "Compute potential energy") .def("getEnergy", &StructuralMechanicsModel::getEnergy, - "Compute the specified energy"); + "Compute the specified energy") -} // End: register structural mechanical model + .def( + "getLumpedMass", + [](const StructuralMechanicsModel & self) -> decltype(auto) { + return self.getLumpedMass(); + }, + py::return_value_policy::reference_internal) + .def( + "getMass", + [](const StructuralMechanicsModel & self) -> decltype(auto) { + return self.getMass(); + }, + py::return_value_policy::reference_internal) + .def("assembleLumpedMassMatrix", + &StructuralMechanicsModel::assembleLumpedMassMatrix, + "Assembles the lumped mass matrix") + .def("hasLumpedMass", &StructuralMechanicsModel::hasLumpedMass); +} } // namespace akantu diff --git a/src/common/aka_array.hh b/src/common/aka_array.hh index 3a346fc5d..21d980519 100644 --- a/src/common/aka_array.hh +++ b/src/common/aka_array.hh @@ -1,445 +1,450 @@ /** * @file aka_array.hh * * @author Till Junge * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Sun Nov 22 2020 * * @brief Array container for Akantu This container differs from the * std::vector from the fact it as 2 dimensions a main dimension and the size * stored per entries * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * 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 . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_types.hh" /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #ifndef AKANTU_ARRAY_HH_ #define AKANTU_ARRAY_HH_ namespace akantu { /// class that afford to store vectors in static memory // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) class ArrayBase { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: explicit ArrayBase(const ID & id = "") : id(id) {} ArrayBase(const ArrayBase & other, const ID & id = "") { this->id = (id.empty()) ? other.id : id; } ArrayBase(ArrayBase && other) = default; ArrayBase & operator=(const ArrayBase & other) = default; ArrayBase & operator=(ArrayBase && other) noexcept = default; virtual ~ArrayBase() = default; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get the amount of space allocated in bytes virtual UInt getMemorySize() const = 0; // changed empty to match std::vector empty inline bool empty() const __attribute__((warn_unused_result)) { return size_ == 0; } /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const = 0; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// Get the Size of the Array UInt size() const { return size_; } /// Get the number of components AKANTU_GET_MACRO(NbComponent, nb_component, UInt); /// Get the name of th array AKANTU_GET_MACRO(ID, id, const ID &); /// Set the name of th array AKANTU_SET_MACRO(ID, id, const ID &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// id of the vector ID id; /// the size used UInt size_{0}; /// number of components UInt nb_component{1}; }; /* -------------------------------------------------------------------------- */ namespace { template struct IteratorHelper {}; template struct IteratorHelper<0, T> { using type = T; }; template struct IteratorHelper<1, T> { using type = Vector; }; template struct IteratorHelper<2, T> { using type = Matrix; }; template struct IteratorHelper<3, T> { using type = Tensor3; }; template using IteratorHelper_t = typename IteratorHelper::type; } // namespace /* -------------------------------------------------------------------------- */ /* Memory handling layer */ /* -------------------------------------------------------------------------- */ enum class ArrayAllocationType { _default, _pod, }; template struct ArrayAllocationTrait : public std::conditional_t< std::is_scalar::value, std::integral_constant, std::integral_constant> {}; /* -------------------------------------------------------------------------- */ template ::value> class ArrayDataLayer : public ArrayBase { public: using value_type = T; using reference = value_type &; using pointer_type = value_type *; using const_reference = const value_type &; public: ~ArrayDataLayer() override = default; /// Allocation of a new vector explicit ArrayDataLayer(UInt size = 0, UInt nb_component = 1, const ID & id = ""); /// Allocation of a new vector with a default value ArrayDataLayer(UInt size, UInt nb_component, const_reference value, const ID & id = ""); /// Copy constructor (deep copy) ArrayDataLayer(const ArrayDataLayer & vect, const ID & id = ""); /// Copy constructor (deep copy) explicit ArrayDataLayer(const std::vector & vect); // copy operator ArrayDataLayer & operator=(const ArrayDataLayer & other); // move constructor ArrayDataLayer(ArrayDataLayer && other) noexcept = default; // move assign ArrayDataLayer & operator=(ArrayDataLayer && other) noexcept = default; protected: // deallocate the memory virtual void deallocate() {} // allocate the memory virtual void allocate(UInt size, UInt nb_component); // allocate and initialize the memory virtual void allocate(UInt size, UInt nb_component, const T & value); public: /// append a tuple of size nb_component containing value inline void push_back(const_reference value); /// append a vector // inline void push_back(const value_type new_elem[]); /// append a Vector or a Matrix template