diff --git a/examples/python/solver_callback/CMakeLists.txt b/examples/python/solver_callback/CMakeLists.txt new file mode 100644 index 000000000..4f7e8017e --- /dev/null +++ b/examples/python/solver_callback/CMakeLists.txt @@ -0,0 +1,35 @@ +#=============================================================================== +# @file CMakeLists.txt +# +# @author Nicolas Richart +# +# @brief CMakeLists for solid mechanics dynamics example +# +# +# @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 . +# +#=============================================================================== + + +add_mesh(solver_callback_mesh bar.geo DIM 2) +register_example(solver_callback + SCRIPT solver_callback.py + PYTHON + FILES_TO_COPY material.dat + DEPENDS solver_callback_mesh) diff --git a/examples/python/solver_callback/bar.geo b/examples/python/solver_callback/bar.geo new file mode 100644 index 000000000..cf7a819d3 --- /dev/null +++ b/examples/python/solver_callback/bar.geo @@ -0,0 +1,35 @@ +// Mesh size +h = 0.05; + +h1 = h; +h2 = h; + +// Dimensions of the bar +Lx = 10; +Ly = 1; + +// ------------------------------------------ +// Geometry +// ------------------------------------------ + +Point(101) = { 0.0, -Ly/2, 0.0, h1}; +Point(102) = { Lx, -Ly/2, 0.0, h2}; + +Point(103) = { Lx, Ly/2., 0.0, h2}; +Point(104) = { 0.0, Ly/2., 0.0, h1}; + +Line(201) = {101, 102}; +Line(202) = {102, 103}; +Line(203) = {103, 104}; +Line(204) = {104, 101}; + +Line Loop(301) = {201, 202, 203, 204}; +Plane Surface(301) = {301}; + +Transfinite Surface "*"; +Recombine Surface "*"; +Physical Surface("Body") = {301}; + +Physical Line("YBlocked") = {201, 203}; +Physical Line("Right") = {202}; +Physical Line("Left") = {204}; diff --git a/examples/python/solver_callback/material.dat b/examples/python/solver_callback/material.dat new file mode 100644 index 000000000..42b9b8ae7 --- /dev/null +++ b/examples/python/solver_callback/material.dat @@ -0,0 +1,6 @@ +material elastic [ + name = fictive + rho = 1. # density + E = 1. # young modulus + nu = .3 # poisson ratio +] diff --git a/examples/python/solver_callback/solver_callback.py b/examples/python/solver_callback/solver_callback.py new file mode 100644 index 000000000..85729bc31 --- /dev/null +++ b/examples/python/solver_callback/solver_callback.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +""" solver_callback.py: solver_callback overload example""" + +__author__ = "Nicolas Richart" +__credits__ = [ + "Guillaume Anciaux ", + "Nicolas Richart ", +] +__copyright__ = "Copyright (©) 2016-2021 EPFL (Ecole Polytechnique Fédérale" \ + " de Lausanne) Laboratory (LSMS - Laboratoire de Simulation" \ + " en Mécanique des Solides)" +__license__ = "LGPLv3" + +import numpy as np +import akantu as aka + + +class SolverCallback(aka.InterceptSolverCallback): + def __init__(self, model): + super().__init__(model) + self.model = model + + mesh = model.getMesh() + left = mesh.getElementGroup("Left").getNodeGroup().getNodes() + right = mesh.getElementGroup("Right").getNodeGroup().getNodes() + position = mesh.getNodes() + + self.pair = [] + for node_l in left: + node_l = int(node_l) + for node_r in right: + node_r = int(node_r) + if abs(position[node_r, 1] - position[node_l, 1]) < 1e-6: + self.pair.append([node_l, node_r]) + + blocked_dofs = model.getBlockedDOFs() + self.periodic_K_modif = aka.TermsToAssemble("displacement", "displacement") + + matrix_type = self.model.getMatrixType("K") + for p in self.pair: + #blocked_dofs[p[1]] = True + # a u_{i, x} + b u_{j, x} = 0 + # self.periodic_K_modif(i*dim + aka._x, i*dim + aka._x, a) + # self.periodic_K_modif(i*dim + aka._x, j*dim + aka._x, b) + + self.periodic_K_modif(p[0]*2, p[0]*2, 1) + self.periodic_K_modif(p[0]*2, p[1]*2, -1) + if matrix_type == aka._unsymmetric: + self.periodic_K_modif(p[1]*2, p[0]*2, -1) + self.periodic_K_modif(p[1]*2, p[1]*2, 1) + + self.first = True + self.k_release = -1 + + def assembleMatrix(self, matrix_id): + self.model.assembleMatrix(matrix_id) + if matrix_id == "K": + release = self.model.getDOFManager().getMatrix("K").getRelease() + if release == self.k_release: + return + + if self.first: + self.model.getDOFManager().getMatrix("K").saveMatrix("K0.mtx") + + self.model.getDOFManager().assemblePreassembledMatrix( + "K", self.periodic_K_modif) + + if self.first: + self.model.getDOFManager().getMatrix("K").saveMatrix("K1.mtx") + + self.k_release = self.model.getDOFManager().getMatrix("K").getRelease() + self.first = False + + def assembleResidual(self): + displacement = self.model.getDisplacement() + force = np.zeros(displacement.shape) + for p in self.pair: + force[p[0], 0] += displacement[p[0], 0] - displacement[p[1], 0] + force[p[1], 0] += displacement[p[1], 0] - displacement[p[0], 0] + self.model.getDOFManager().assembleToResidual('displacement', force, -1.); + self.model.assembleResidual(); + +# ----------------------------------------------------------------------------- +def main(): + spatial_dimension = 2 + mesh_file = 'bar.msh' + max_steps = 250 + time_step = 1e-3 + + aka.parseInput('material.dat') + + # ------------------------------------------------------------------------- + # Initialization + # ------------------------------------------------------------------------- + mesh = aka.Mesh(spatial_dimension) + mesh.read(mesh_file) + + model = aka.SolidMechanicsModel(mesh) + + model.initFull(_analysis_method=aka._implicit_dynamic) + + model.setBaseName("solver_callback") + model.addDumpFieldVector("displacement") + model.addDumpFieldVector("acceleration") + model.addDumpFieldVector("velocity") + model.addDumpFieldVector("internal_force") + model.addDumpFieldVector("external_force") + model.addDumpField("strain") + model.addDumpField("stress") + model.addDumpField("blocked_dofs") + + # ------------------------------------------------------------------------- + # boundary conditions + # ------------------------------------------------------------------------- + model.applyBC(aka.FixedValue(0, aka._y), "YBlocked") + + # ------------------------------------------------------------------------- + # initial conditions + # ------------------------------------------------------------------------- + displacement = model.getDisplacement() + velocity = model.getVelocity() + nb_nodes = mesh.getNbNodes() + position = mesh.getNodes() + + L = 1 # pulse_width + A = 0.01 + v = np.sqrt(model.getMaterial(0).getReal('E') / + model.getMaterial(0).getReal('rho')) + k = 0.1 * 2 * np.pi * 3 / L + t = 0. + velocity[:, 0] = k * v * A * np.sin(k * ((position[:, 0] - 5.) - v * t)) + displacement[:, 0] = A * np.cos(k * ((position[:, 0] - 5.) - v * t)) + + # ------------------------------------------------------------------------- + # timestep value computation + # ------------------------------------------------------------------------- + time_factor = 0.8 + stable_time_step = model.getStableTimeStep() * time_factor + + print("Stable Time Step = {0}".format(stable_time_step)) + print("Required Time Step = {0}".format(time_step)) + + time_step = stable_time_step * time_factor + + model.setTimeStep(time_step) + solver_callback = SolverCallback(model) + + solver = model.getNonLinearSolver() + solver.set("max_iterations", 100) + solver.set("threshold", 1e-7) + + # ------------------------------------------------------------------------- + # loop for evolution of motion dynamics + # ------------------------------------------------------------------------- + print("step,step * time_step,epot,ekin,epot + ekin") + for step in range(0, max_steps + 1): + + model.solveStep(solver_callback) + #model.solveStep() + + if step % 10 == 0: + model.dump() + + epot = model.getEnergy('potential') + ekin = model.getEnergy('kinetic') + + # output energy calculation to screen + print("{0},{1},{2},{3},{4}".format(step, step * time_step, + epot, ekin, + (epot + ekin))) + + return + + +# ----------------------------------------------------------------------------- +if __name__ == "__main__": + main() diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 9cbc35a5d..a58bfb77a 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,144 +1,145 @@ #=============================================================================== # @file CMakeLists.txt # # @author Guillaume Anciaux # @author Nicolas Richart # # @date creation: Fri Dec 12 2014 # @date last modification: Fri May 07 2021 # # @brief CMake file for the python wrapping of akantu # # # @section LICENSE # # Copyright (©) 2015-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 . # #=============================================================================== if(NOT SKBUILD) package_get_all_include_directories( AKANTU_LIBRARY_INCLUDE_DIRS ) package_get_all_external_informations( PRIVATE_INCLUDE AKANTU_PRIVATE_EXTERNAL_INCLUDE_DIR INTERFACE_INCLUDE AKANTU_INTERFACE_EXTERNAL_INCLUDE_DIR LIBRARIES AKANTU_EXTERNAL_LIBRARIES ) endif() set(PYAKANTU_SRCS py_aka_common.cc py_aka_error.cc py_akantu.cc py_boundary_conditions.cc + py_dof_manager.cc py_fe_engine.cc py_group_manager.cc py_mesh.cc py_model.cc py_parser.cc py_solver.cc ) package_is_activated(iohelper _is_activated) if (_is_activated) list(APPEND PYAKANTU_SRCS py_dumpable.cc ) endif() package_is_activated(solid_mechanics _is_activated) if (_is_activated) list(APPEND PYAKANTU_SRCS py_solid_mechanics_model.cc py_material.cc py_material_selector.cc ) endif() package_is_activated(cohesive_element _is_activated) if (_is_activated) list(APPEND PYAKANTU_SRCS py_solid_mechanics_model_cohesive.cc py_fragment_manager.cc ) endif() package_is_activated(heat_transfer _is_activated) if (_is_activated) list(APPEND PYAKANTU_SRCS py_heat_transfer_model.cc ) endif() package_is_activated(contact_mechanics _is_activated) if(_is_activated) list(APPEND PYAKANTU_SRCS py_contact_mechanics_model.cc py_model_couplers.cc ) endif() package_is_activated(phase_field _is_activated) if (_is_activated) list(APPEND PYAKANTU_SRCS py_phase_field_model.cc ) endif() package_is_activated(structural_mechanics _is_activated) if (_is_activated) list(APPEND PYAKANTU_SRCS py_structural_mechanics_model.cc ) endif() pybind11_add_module(py11_akantu ${PYAKANTU_SRCS}) # to avoid compilation warnings from pybind11 target_include_directories(py11_akantu SYSTEM BEFORE PRIVATE ${PYBIND11_INCLUDE_DIR} PRIVATE ${pybind11_INCLUDE_DIR} PRIVATE ${PYTHON_INCLUDE_DIRS}) target_link_libraries(py11_akantu PUBLIC akantu) set_target_properties(py11_akantu PROPERTIES DEBUG_POSTFIX "" LIBRARY_OUTPUT_DIRECTORY akantu) file(COPY akantu DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) if(NOT SKBUILD) set(_python_install_dir ${CMAKE_INSTALL_LIBDIR}/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages) else() set(_python_install_dir .) endif() install(TARGETS py11_akantu LIBRARY DESTINATION ${_python_install_dir}) if(NOT SKBUILD) install(DIRECTORY akantu DESTINATION ${_python_install_dir} FILES_MATCHING PATTERN "*.py") endif() diff --git a/python/py_akantu.cc b/python/py_akantu.cc index 43958335b..3c88c1e5c 100644 --- a/python/py_akantu.cc +++ b/python/py_akantu.cc @@ -1,171 +1,174 @@ /** * @file py_akantu.cc * * @author Guillaume Anciaux * @author Philip Mueller * @author Mohit Pundir * @author Nicolas Richart * * @date creation: Wed Oct 31 2018 * @date last modification: Mon Mar 29 2021 * * @brief pybind11 interface to akantu main's file * * * @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 "aka_config.hh" /* -------------------------------------------------------------------------- */ #include "py_aka_common.hh" #include "py_aka_error.hh" #include "py_boundary_conditions.hh" +#include "py_dof_manager.hh" #include "py_fe_engine.hh" #include "py_group_manager.hh" #include "py_mesh.hh" #include "py_model.hh" #include "py_parser.hh" #include "py_solver.hh" #if defined(AKANTU_USE_IOHELPER) #include "py_dumpable.hh" #endif #if defined(AKANTU_SOLID_MECHANICS) #include "py_material.hh" #include "py_material_selector.hh" #include "py_solid_mechanics_model.hh" #endif #if defined(AKANTU_HEAT_TRANSFER) #include "py_heat_transfer_model.hh" #endif #if defined(AKANTU_COHESIVE_ELEMENT) #include "py_fragment_manager.hh" #include "py_solid_mechanics_model_cohesive.hh" #endif #if defined(AKANTU_CONTACT_MECHANICS) #include "py_contact_mechanics_model.hh" #include "py_model_couplers.hh" #endif #if defined(AKANTU_PHASE_FIELD) #include "py_phase_field_model.hh" #endif #if defined(AKANTU_STRUCTURAL_MECHANICS) #include "py_structural_mechanics_model.hh" #endif /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ namespace py = pybind11; namespace akantu { void register_all(pybind11::module & mod) { register_initialize(mod); register_enums(mod); register_error(mod); register_functions(mod); register_parser(mod); register_solvers(mod); register_group_manager(mod); #if defined(AKANTU_USE_IOHELPER) register_dumpable(mod); #endif register_mesh(mod); register_fe_engine(mod); + register_dof_manager(mod); + register_boundary_conditions(mod); register_model(mod); #if defined(AKANTU_HEAT_TRANSFER) register_heat_transfer_model(mod); #endif #if defined(AKANTU_SOLID_MECHANICS) register_solid_mechanics_model(mod); register_material(mod); register_material_selector(mod); #endif #if defined(AKANTU_COHESIVE_ELEMENT) register_solid_mechanics_model_cohesive(mod); register_fragment_manager(mod); #endif #if defined(AKANTU_STRUCTURAL_MECHANICS) register_structural_mechanics_model(mod); #endif #if defined(AKANTU_CONTACT_MECHANICS) register_contact_mechanics_model(mod); register_model_couplers(mod); #endif #if defined(AKANTU_PHASE_FIELD) register_phase_field_model(mod); register_phase_field_coupler(mod); #endif } } // namespace akantu /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ PYBIND11_MODULE(py11_akantu, mod) { mod.doc() = "Akantu python interface"; static py::exception akantu_exception(mod, "Exception"); py::register_exception_translator([](std::exception_ptr ptr) { try { if (ptr) { std::rethrow_exception(ptr); } } catch (akantu::debug::Exception & e) { if (akantu::debug::debugger.printBacktrace()) { akantu::debug::printBacktrace(); } akantu_exception(e.info().c_str()); } }); akantu::register_all(mod); mod.def("has_mpi", []() { #if defined(AKANTU_USE_MPI) return true; #else return false; #endif }); } // Module akantu diff --git a/python/py_dof_manager.cc b/python/py_dof_manager.cc new file mode 100644 index 000000000..b0b457d87 --- /dev/null +++ b/python/py_dof_manager.cc @@ -0,0 +1,211 @@ +/* + * 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 +/* -------------------------------------------------------------------------- */ +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::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, "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_dof_manager.hh b/python/py_dof_manager.hh new file mode 100644 index 000000000..c1983c04f --- /dev/null +++ b/python/py_dof_manager.hh @@ -0,0 +1,32 @@ +/* + * 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 + +#ifndef AKANTU_PY_DOF_MANAGER_HH_ +#define AKANTU_PY_DOF_MANAGER_HH_ + +namespace akantu { + +void register_dof_manager(pybind11::module & mod); + +} + +#endif // AKANTU_PY_DOF_MANAGER_HH_ diff --git a/python/py_model.cc b/python/py_model.cc index 7978dcc67..fe0718911 100644 --- a/python/py_model.cc +++ b/python/py_model.cc @@ -1,159 +1,128 @@ /** * @file py_model.cc * * @author Guillaume Anciaux * @author Emil Gallyamov * @author Philip Mueller * @author Mohit Pundir * @author Nicolas Richart * * @date creation: Sun Jun 16 2019 * @date last modification: Sat Mar 13 2021 * * @brief pybind11 interface to Model and parent classes * * * @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 +#include #include /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ namespace py = pybind11; /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ void register_model(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::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, "ModelSolver", - py::multiple_inheritance()) + py::class_(mod, "ModelSolver", + py::multiple_inheritance()) .def("getNonLinearSolver", (NonLinearSolver & (ModelSolver::*)(const ID &)) & ModelSolver::getNonLinearSolver, py::arg("solver_id") = "", py::return_value_policy::reference) - .def("solveStep", [](ModelSolver & self) { self.solveStep(); }) - .def("solveStep", [](ModelSolver & self, const ID & solver_id) { - self.solveStep(solver_id); - }); + .def( + "solveStep", + [](ModelSolver & self, const ID & solver_id) { + self.solveStep(solver_id); + }, + py::arg("solver_id") = "") + .def( + "solveStep", + [](ModelSolver & self, SolverCallback & callback, + const ID & solver_id) { self.solveStep(callback, solver_id); }, + py::arg("callback"), py::arg("solver_id") = ""); py::class_(mod, "Model", py::multiple_inheritance()) .def("setBaseName", &Model::setBaseName) .def("setDirectory", &Model::setDirectory) .def("getFEEngine", &Model::getFEEngine, py::arg("name") = "", py::return_value_policy::reference) .def("getFEEngineBoundary", &Model::getFEEngine, py::arg("name") = "", py::return_value_policy::reference) .def("addDumpFieldVector", &Model::addDumpFieldVector) .def("addDumpField", &Model::addDumpField) .def("setBaseNameToDumper", &Model::setBaseNameToDumper) .def("addDumpFieldVectorToDumper", &Model::addDumpFieldVectorToDumper) .def("addDumpFieldToDumper", &Model::addDumpFieldToDumper) .def("dump", [](Model & self) { self.dump(); }) .def( "dump", [](Model & self, UInt step) { self.dump(step); }, py::arg("step")) .def( "dump", [](Model & self, Real time, UInt step) { self.dump(time, step); }, py::arg("time"), py::arg("step")) .def( "dump", [](Model & self, const std::string & dumper) { self.dump(dumper); }, py::arg("dumper_name")) .def( "dump", [](Model & self, const std::string & dumper, UInt step) { self.dump(dumper, step); }, py::arg("dumper_name"), py::arg("step")) .def( "dump", [](Model & self, const std::string & dumper, Real time, UInt step) { self.dump(dumper, time, step); }, py::arg("dumper_name"), py::arg("time"), py::arg("step")) .def("initNewSolver", &Model::initNewSolver) .def( "getNewSolver", [](Model & self, const std::string id, const TimeStepSolverType & time, const NonLinearSolverType & type) { self.getNewSolver(id, time, type); }, py::return_value_policy::reference) .def("setIntegrationScheme", [](Model & self, const std::string id, const std::string primal, const IntegrationSchemeType & scheme) { self.setIntegrationScheme(id, primal, scheme); }) .def("getDOFManager", &Model::getDOFManager, py::return_value_policy::reference) .def("assembleMatrix", &Model::assembleMatrix); } } // namespace akantu diff --git a/python/py_solid_mechanics_model.cc b/python/py_solid_mechanics_model.cc index 1f698389f..e5d823f0c 100644 --- a/python/py_solid_mechanics_model.cc +++ b/python/py_solid_mechanics_model.cc @@ -1,164 +1,165 @@ /** * @file py_solid_mechanics_model.cc * * @author Guillaume Anciaux * @author Mohit Pundir * @author Nicolas Richart * * @date creation: Sun Jun 16 2019 * @date last modification: Sat Mar 13 2021 * * @brief pybind11 interface to SolidMechanicsModel * * * @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 /* -------------------------------------------------------------------------- */ #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, \ [](SolidMechanicsModel & self) -> decltype(auto) { \ return self.func_name(); \ }, \ py::return_value_policy::reference) #define def_function(func_name) \ def(#func_name, [](SolidMechanicsModel & self) -> decltype(auto) { \ return self.func_name(); \ }) + /* -------------------------------------------------------------------------- */ void register_solid_mechanics_model(py::module & mod) { py::class_(mod, "SolidMechanicsModelOptions") .def(py::init(), py::arg("_analysis_method") = _explicit_lumped_mass); py::class_(mod, "SolidMechanicsModel", py::multiple_inheritance()) .def(py::init, const ModelType>(), py::arg("mesh"), py::arg("spatial_dimension") = _all_dimensions, py::arg("id") = "solid_mechanics_model", py::arg("dof_manager") = nullptr, py::arg("model_type") = ModelType::_solid_mechanics_model) .def( "initFull", [](SolidMechanicsModel & self, const SolidMechanicsModelOptions & options) { self.initFull(options); }, py::arg("option") = SolidMechanicsModelOptions()) .def( "initFull", [](SolidMechanicsModel & self, const AnalysisMethod & analysis_method) { self.initFull(_analysis_method = analysis_method); }, py::arg("_analysis_method")) .def_deprecated("applyDirichletBC", "Deprecated: use applyBC") .def("applyBC", [](SolidMechanicsModel & self, BC::Dirichlet::DirichletFunctor & func, const std::string & element_group) { self.applyBC(func, element_group); }) .def("applyBC", [](SolidMechanicsModel & self, BC::Neumann::NeumannFunctor & func, const std::string & element_group) { self.applyBC(func, element_group); }) .def("setTimeStep", &SolidMechanicsModel::setTimeStep, py::arg("time_step"), py::arg("solver_id") = "") .def( "getEnergy", [](SolidMechanicsModel & self, const std::string & energy_id) { return self.getEnergy(energy_id); }, py::arg("energy_id")) .def( "getEnergy", [](SolidMechanicsModel & self, const std::string & energy_id, const std::string & group_id) { return self.getEnergy(energy_id, group_id); }, py::arg("energy_id"), py::arg("group_id")) .def_function(assembleStiffnessMatrix) .def_function(assembleInternalForces) .def_function(assembleMass) .def_function(assembleMassLumped) .def_function(getStableTimeStep) .def_function_nocopy(getExternalForce) .def_function_nocopy(getDisplacement) .def_function_nocopy(getPreviousDisplacement) .def_function_nocopy(getCurrentPosition) .def_function_nocopy(getIncrement) .def_function_nocopy(getInternalForce) .def_function_nocopy(getMass) .def_function_nocopy(getVelocity) .def_function_nocopy(getAcceleration) .def_function_nocopy(getInternalForce) .def_function_nocopy(getBlockedDOFs) .def_function_nocopy(getMesh) .def( "getMaterial", [](SolidMechanicsModel & self, UInt material_id) -> decltype(auto) { return self.getMaterial(material_id); }, py::arg("material_id"), py::return_value_policy::reference) .def( "getMaterial", [](SolidMechanicsModel & self, const ID & material_name) -> decltype(auto) { return self.getMaterial(material_name); }, py::arg("material_name"), py::return_value_policy::reference) .def("getMaterialIndex", &SolidMechanicsModel::getMaterialIndex) // .def( // "setMaterialSelector", // [](SolidMechanicsModel & self, MaterialSelector & // material_selector) { // self.setMaterialSelector(material_selector.shared_from_this()); // }) .def("setMaterialSelector", [](SolidMechanicsModel & self, std::shared_ptr material_selector) { std::cout << (*material_selector)(ElementNull) << std::endl; self.setMaterialSelector(material_selector); }) .def("getMaterialSelector", &SolidMechanicsModel::getMaterialSelector); } } // namespace akantu diff --git a/python/py_solver.cc b/python/py_solver.cc index e8dcd435f..f2c83cfe6 100644 --- a/python/py_solver.cc +++ b/python/py_solver.cc @@ -1,84 +1,105 @@ /** * @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("__call__", [](const SparseMatrix & self, UInt i, UInt j) { - return self(i, j); - }); + .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"); + + 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/src/fe_engine/fe_engine_template.hh b/src/fe_engine/fe_engine_template.hh index 296ca2117..545629934 100644 --- a/src/fe_engine/fe_engine_template.hh +++ b/src/fe_engine/fe_engine_template.hh @@ -1,431 +1,431 @@ /** * @file fe_engine_template.hh * * @author Guillaume Anciaux * @author Sébastien Hartmann * @author Mohit Pundir * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Fri May 14 2021 * * @brief templated class that calls integration and shape objects * * * @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 "fe_engine.hh" #include "integrator.hh" #include "shape_functions.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #ifndef AKANTU_FE_ENGINE_TEMPLATE_HH_ #define AKANTU_FE_ENGINE_TEMPLATE_HH_ namespace akantu { class DOFManager; namespace fe_engine { namespace details { template struct AssembleLumpedTemplateHelper; template struct AssembleFieldMatrixHelper; } // namespace details } // namespace fe_engine template struct AssembleFieldMatrixStructHelper; struct DefaultIntegrationOrderFunctor { template static inline constexpr int getOrder() { return ElementClassProperty::polynomial_degree; } }; /* -------------------------------------------------------------------------- */ template