diff --git a/examples/python/custom-material/bi-material.py b/examples/python/custom-material/bi-material.py index ad99a4add..9af2925e0 100644 --- a/examples/python/custom-material/bi-material.py +++ b/examples/python/custom-material/bi-material.py @@ -1,201 +1,196 @@ -from __future__ import print_function -# ------------------------------------------------------------- # import akantu as aka import subprocess import numpy as np import time import os # ------------------------------------------------------------- # class LocalElastic(aka.Material): def __init__(self, model, _id): super().__init__(model, _id) - super().registerParamReal('E', aka._pat_readable, 'Youngs modulus') - + super().registerParamReal('E', + aka._pat_readable | aka._pat_parsable, + 'Youngs modulus') + super().registerParamReal('nu', + aka._pat_readable | aka._pat_parsable, + 'Poisson ratio') # declares all the internals - def initMaterial(self, internals, params): - self.E = params['E'] - self.nu = params['nu'] - self.rho = params['rho'] - # print(self.__dict__) - # First Lame coefficient - self.lame_lambda = self.nu * self.E / ( - (1. + self.nu) * (1. - 2. * self.nu)) + def initMaterial(self): + nu = self.getReal('nu') + E = self.getReal('E') + self.lbda = nu * E / ((1 + nu) * (1 - 2 * nu)); + self.mu = E / (2 * (1 + nu)); + self.lame_lambda = nu * E / ( + (1. + nu) * (1. - 2. * nu)) # Second Lame coefficient (shear modulus) - self.lame_mu = self.E / (2. * (1. + self.nu)) - - all_factor = internals['factor'] - all_quad_coords = internals['quad_coordinates'] - - for elem_type in all_factor.keys(): - factor = all_factor[elem_type] - quad_coords = all_quad_coords[elem_type] - - factor[:] = 1. - factor[quad_coords[:, 1] < 0.5] = .5 - + self.lame_mu = E / (2. * (1. + nu)) + super().initMaterial() + # declares all the internals @staticmethod def registerInternals(): return ['potential', 'factor'] # declares all the internals @staticmethod def registerInternalSizes(): return [1, 1] # declares all the parameters that could be parsed @staticmethod def registerParam(): return ['E', 'nu'] # declares all the parameters that are needed def getPushWaveSpeed(self, params): return np.sqrt((self.lame_lambda + 2 * self.lame_mu) / self.rho) # compute small deformation tensor @staticmethod def computeEpsilon(grad_u): return 0.5 * (grad_u + np.einsum('aij->aji', grad_u)) # constitutive law - def computeStress(self, grad_u, sigma, internals, params): + def computeStress(self, el_type, ghost_type): + + grad_u = self.getGradU(el_type, ghost_type) + sigma = self.getStress(el_type, ghost_type) + n_quads = grad_u.shape[0] grad_u = grad_u.reshape((n_quads, 2, 2)) - factor = internals['factor'].reshape(n_quads) + # factor = internals['factor'].reshape(n_quads) epsilon = self.computeEpsilon(grad_u) sigma = sigma.reshape((n_quads, 2, 2)) trace = np.einsum('aii->a', grad_u) sigma[:, :, :] = ( np.einsum('a,ij->aij', trace, self.lame_lambda * np.eye(2)) + 2. * self.lame_mu * epsilon) # print(sigma.reshape((n_quads, 4))) # print(grad_u.reshape((n_quads, 4))) - sigma[:, :, :] = np.einsum('aij, a->aij', sigma, factor) + # sigma[:, :, :] = np.einsum('aij, a->aij', sigma, factor) # constitutive law tangent modulii - def computeTangentModuli(self, grad_u, tangent, internals, params): - n_quads = tangent.shape[0] - tangent = tangent.reshape(n_quads, 3, 3) - factor = internals['factor'].reshape(n_quads) + def computeTangentModuli(self, el_type, tangent_matrix, ghost_type): + n_quads = tangent_matrix.shape[0] + tangent = tangent_matrix.reshape(n_quads, 3, 3) + # factor = internals['factor'].reshape(n_quads) Miiii = self.lame_lambda + 2 * self.lame_mu Miijj = self.lame_lambda Mijij = self.lame_mu tangent[:, 0, 0] = Miiii tangent[:, 1, 1] = Miiii tangent[:, 0, 1] = Miijj tangent[:, 1, 0] = Miijj tangent[:, 2, 2] = Mijij - tangent[:, :, :] = np.einsum('aij, a->aij', tangent, factor) + # tangent[:, :, :] = np.einsum('aij, a->aij', tangent, factor) # computes the energy density def getEnergyDensity(self, energy_type, energy_density, grad_u, stress, internals, params): nquads = stress.shape[0] stress = stress.reshape(nquads, 2, 2) grad_u = grad_u.reshape((nquads, 2, 2)) if energy_type != 'potential': raise RuntimeError('not known energy') epsilon = self.computeEpsilon(grad_u) energy_density[:, 0] = ( 0.5 * np.einsum('aij,aij->a', stress, epsilon)) # applies manually the boundary conditions def applyBC(model): nbNodes = model.getMesh().getNbNodes() position = model.getMesh().getNodes() displacement = model.getDisplacement() blocked_dofs = model.getBlockedDOFs() width = 1. height = 1. epsilon = 1e-8 for node in range(0, nbNodes): if((np.abs(position[node, 0]) < epsilon) or # left side (np.abs(position[node, 0] - width) < epsilon)): # right side blocked_dofs[node, 0] = True displacement[node, 0] = 0 * position[node, 0] + 0. if(np.abs(position[node, 1]) < epsilon): # lower side blocked_dofs[node, 1] = True displacement[node, 1] = - 1. if(np.abs(position[node, 1] - height) < epsilon): # upper side blocked_dofs[node, 1] = True displacement[node, 1] = 1. # main parameters spatial_dimension = 2 mesh_file = 'square.msh' if not os.path.isfile(mesh_file): # call gmsh to generate the mesh ret = subprocess.call( 'gmsh -format msh2 -2 square.geo -optimize square.msh', shell=True) if ret != 0: raise Exception( 'execution of GMSH failed: do you have it installed ?') time.sleep(2) # read mesh mesh = aka.Mesh(spatial_dimension) mesh.read(mesh_file) # create the custom material # mat = LocalElastic() mat_factory = aka.MaterialFactory.getInstance() def allocator(_dim, _unused, model, _id): return LocalElastic(model, _id) mat_factory.registerAllocator("local_elastic", allocator) # parse input file aka.parseInput('material.dat') # init the SolidMechanicsModel -print(dir(aka)) model = aka.SolidMechanicsModel(mesh) model.initFull(_analysis_method=aka._static) # configure the solver solver = model.getNonLinearSolver() solver.set("max_iterations", 2) solver.set("threshold", 1e-3) solver.set("convergence_type", aka._scc_solution) # prepare the dumper model.setBaseName("bimaterial") model.addDumpFieldVector("displacement") model.addDumpFieldVector("internal_force") model.addDumpFieldVector("external_force") model.addDumpField("strain") model.addDumpField("stress") -model.addDumpField("factor") +# model.addDumpField("factor") model.addDumpField("blocked_dofs") # Boundary conditions applyBC(model) # solve the problem model.solveStep() # dump paraview files model.dump() diff --git a/packages/python_interface.cmake b/packages/python_interface.cmake index a94ab468b..f10898285 100644 --- a/packages/python_interface.cmake +++ b/packages/python_interface.cmake @@ -1,81 +1,82 @@ #=============================================================================== # @file python_interface.cmake # # @author Guillaume Anciaux # @author Nicolas Richart # # @date creation: Tue Nov 29 2011 # @date last modification: Fri Jan 22 2016 # # @brief package description for the python interface # # @section LICENSE # # Copyright (©) 2010-2012, 2014, 2015 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 . # #=============================================================================== package_declare(python_interface DESCRIPTION "Akantu's python interface" DEPENDS PythonLibs) package_declare_sources(python_interface python/python_functor.cc python/python_functor.hh python/python_functor_inline_impl.cc model/solid_mechanics/materials/material_python/material_python.cc model/solid_mechanics/materials/material_python/material_python.hh ) set(AKANTU_PYTHON_INTERFACE_IMPL "swig" CACHE STRING "Specifies the implementation of the python interface") set_property(CACHE AKANTU_PYTHON_INTERFACE_IMPL PROPERTY STRINGS pybind11 swig all ) if(AKANTU_PYTHON_INTERFACE_IMPL MATCHES "swig" OR AKANTU_PYTHON_INTERFACE_IMPL MATCHES "all") package_add_dependencies(python_interface PRIVATE SWIG) else() package_remove_dependencies(python_interface SWIG) endif() if(AKANTU_PYTHON_INTERFACE_IMPL MATCHES "pybind11" OR AKANTU_PYTHON_INTERFACE_IMPL MATCHES "all") + message("blip") package_add_dependencies(python_interface PUBLIC pybind11) else() package_remove_dependencies(python_interface pybind11) endif() package_set_package_system_dependency(python_interface deb-src swig3.0) package_declare_documentation(python_interface "This package enables the python interface of Akantu. It relies on swig3.0 to generate the code" "" "Under Ubuntu (14.04 LTS) the installation can be performed using the commands:" "\\begin{command}" " > sudo apt-get install swig3.0" "\\end{command}" "" ) package_declare_documentation_files(python_interface manual-python.tex ) diff --git a/python/pybind11/py_aka_common.cc b/python/pybind11/py_aka_common.cc index f4b51c660..95646a8a2 100644 --- a/python/pybind11/py_aka_common.cc +++ b/python/pybind11/py_aka_common.cc @@ -1,134 +1,150 @@ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ #include "integration_point.hh" #include "mesh.hh" -#include "parser.hh" #include "parameter_registry.hh" +#include "parser.hh" /* -------------------------------------------------------------------------- */ namespace { namespace py = pybind11; namespace _aka = akantu; /* -------------------------------------------------------------------------- */ py::module & register_enums(py::module & mod) { py::enum_<_aka::SpatialDirection>(mod, "SpatialDirection") .value("_x", _aka::_x) .value("_y", _aka::_y) .value("_z", _aka::_z) .export_values(); py::enum_<_aka::AnalysisMethod>(mod, "AnalysisMethod") .value("_static", _aka::_static) .value("_implicit_dynamic", _aka::_implicit_dynamic) .value("_explicit_lumped_mass", _aka::_explicit_lumped_mass) .value("_explicit_lumped_capacity", _aka::_explicit_lumped_capacity) .value("_explicit_consistent_mass", _aka::_explicit_consistent_mass) .export_values(); py::enum_<_aka::NonLinearSolverType>(mod, "NonLinearSolverType") .value("_nls_linear", _aka::_nls_linear) .value("_nls_newton_raphson", _aka::_nls_newton_raphson) .value("_nls_newton_raphson_modified", _aka::_nls_newton_raphson_modified) .value("_nls_lumped", _aka::_nls_lumped) .value("_nls_auto", _aka::_nls_auto) .export_values(); py::enum_<_aka::TimeStepSolverType>(mod, "TimeStepSolverType") .value("_tsst_static", _aka::_tsst_static) .value("_tsst_dynamic", _aka::_tsst_dynamic) .value("_tsst_dynamic_lumped", _aka::_tsst_dynamic_lumped) .value("_tsst_not_defined", _aka::_tsst_not_defined) .export_values(); py::enum_<_aka::IntegrationSchemeType>(mod, "IntegrationSchemeType") .value("_ist_pseudo_time", _aka::_ist_pseudo_time) .value("_ist_forward_euler", _aka::_ist_forward_euler) .value("_ist_trapezoidal_rule_1", _aka::_ist_trapezoidal_rule_1) .value("_ist_backward_euler", _aka::_ist_backward_euler) .value("_ist_central_difference", _aka::_ist_central_difference) .value("_ist_fox_goodwin", _aka::_ist_fox_goodwin) .value("_ist_trapezoidal_rule_2", _aka::_ist_trapezoidal_rule_2) .value("_ist_linear_acceleration", _aka::_ist_linear_acceleration) .value("_ist_newmark_beta", _aka::_ist_newmark_beta) .value("_ist_generalized_trapezoidal", _aka::_ist_generalized_trapezoidal) .export_values(); py::enum_<_aka::SolveConvergenceCriteria>(mod, "SolveConvergenceCriteria") .value("_scc_residual", _aka::_scc_residual) .value("_scc_solution", _aka::_scc_solution) .value("_scc_residual_mass_wgh", _aka::_scc_residual_mass_wgh) .export_values(); py::enum_<_aka::CohesiveMethod>(mod, "CohesiveMethod") .value("_intrinsic", _aka::_intrinsic) .value("_extrinsic", _aka::_extrinsic) .export_values(); py::enum_<_aka::GhostType>(mod, "GhostType") .value("_not_ghost", _aka::_not_ghost) .value("_ghost", _aka::_ghost) .value("_casper", _aka::_casper) .export_values(); py::enum_<_aka::MeshIOType>(mod, "MeshIOType") .value("_miot_auto", _aka::_miot_auto) .value("_miot_gmsh", _aka::_miot_gmsh) .value("_miot_gmsh_struct", _aka::_miot_gmsh_struct) .value("_miot_diana", _aka::_miot_diana) .value("_miot_abaqus", _aka::_miot_abaqus) .export_values(); - py::enum_<_aka::ParameterAccessType>(mod, "ParameterAccessType") + py::enum_<_aka::ParameterAccessType>(mod, "ParameterAccessType", + py::arithmetic()) .value("_pat_internal", _aka::_pat_internal) .value("_pat_writable", _aka::_pat_writable) .value("_pat_readable", _aka::_pat_readable) .value("_pat_modifiable", _aka::_pat_modifiable) .value("_pat_parsable", _aka::_pat_parsable) .value("_pat_parsmod", _aka::_pat_parsmod) .export_values(); py::enum_<_aka::ModelType>(mod, "ModelType") - .value("_model", _aka::ModelType::_model) .value("_solid_mechanics_model", _aka::ModelType::_solid_mechanics_model) .value("_solid_mechanics_model_cohesive", _aka::ModelType::_solid_mechanics_model_cohesive) .value("_heat_transfer_model", _aka::ModelType::_heat_transfer_model) .value("_structural_mechanics_model", _aka::ModelType::_structural_mechanics_model) .value("_embedded_model", _aka::ModelType::_embedded_model) .export_values(); + py::enum_<_aka::ElementType>(mod, "ElementType") + .value("_point_1", _aka::_point_1) + .value("_segment_2", _aka::_segment_2) + .value("_segment_3", _aka::_segment_3) + .value("_triangle_3", _aka::_triangle_3) + .value("_triangle_6", _aka::_triangle_6) + .value("_quadrangle_4", _aka::_quadrangle_4) + .value("_quadrangle_8", _aka::_quadrangle_8) + .value("_tetrahedron_4", _aka::_tetrahedron_4) + .value("_tetrahedron_10", _aka::_tetrahedron_10) + .value("_pentahedron_6", _aka::_pentahedron_6) + .value("_pentahedron_15", _aka::_pentahedron_15) + .value("_hexahedron_8", _aka::_hexahedron_8) + .value("_hexahedron_20", _aka::_hexahedron_20) + .export_values(); + mod.def("parseInput", [](const std::string & input_file) { _aka::getStaticParser().parse(input_file); }, "Parse an Akantu input file"); py::class_<_aka::Mesh>(mod, "Mesh") .def(py::init<_aka::UInt, const _aka::ID &, const _aka::MemoryID &>(), py::arg("spatial_dimension"), py::arg("id") = "mesh", py::arg("memory_id") = 0) .def("read", &_aka::Mesh::read, py::arg("filename"), py::arg("mesh_io_type") = _aka::_miot_auto, "read the mesh from a file") .def("getNodes", [](_aka::Mesh & self) -> _aka::Array<_aka::Real> { return self.getNodes(); }, py::return_value_policy::reference) .def("getNbNodes", &_aka::Mesh::getNbNodes); py::class_<_aka::IntegrationPoint>(mod, "IntegrationPoint"); return mod; } // namespace } // namespace diff --git a/python/pybind11/py_aka_solid_mechanics_model.cc b/python/pybind11/py_aka_solid_mechanics_model.cc index e80cc188b..f494dd7a8 100644 --- a/python/pybind11/py_aka_solid_mechanics_model.cc +++ b/python/pybind11/py_aka_solid_mechanics_model.cc @@ -1,202 +1,231 @@ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ #include "non_linear_solver.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace py = pybind11; /* -------------------------------------------------------------------------- */ std::map> map_params; /* -------------------------------------------------------------------------- */ namespace akantu { class PyMaterial : public Material { public: /* Inherit the constructors */ using Material::Material; virtual ~PyMaterial(){}; - // void registerInternals(); - // void initMaterial() override; - // void computeStress(ElementType el_type, - // GhostType ghost_type = _not_ghost) override; - // void computeTangentModuli(const ElementType & el_type, - // Array & tangent_matrix, - // GhostType ghost_type = _not_ghost) override; + void initMaterial() override { + PYBIND11_OVERLOAD(void, Material, initMaterial); + }; + void computeStress(ElementType el_type, + GhostType ghost_type = _not_ghost) override { + PYBIND11_OVERLOAD_PURE(void, Material, computeStress, el_type, ghost_type); + } + void computeTangentModuli(const ElementType & el_type, + Array & tangent_matrix, + GhostType ghost_type = _not_ghost) override { + PYBIND11_OVERLOAD_PURE(void, Material, computeTangentModuli, el_type, + tangent_matrix, ghost_type); + } // Real getPushWaveSpeed(const Element & element) const override; // Real getEnergy(const std::string & type) override; // Real getEnergyForType(const std::string & type, ElementType el_type); // protected: // std::map local_params; // std::map>> internals; }; } // namespace akantu /* -------------------------------------------------------------------------- */ namespace _aka = akantu; namespace { /* -------------------------------------------------------------------------- */ #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, \ [](_aka::SolidMechanicsModel & self) -> decltype(auto) { \ return self.func_name(); \ }, \ py::return_value_policy::reference) #define def_function(func_name) \ def(#func_name, [](_aka::SolidMechanicsModel & self) -> decltype(auto) { \ return self.func_name(); \ }) /* -------------------------------------------------------------------------- */ py::module & register_solid_mechanics_models(py::module & mod) { py::class_<_aka::SolidMechanicsModelOptions>(mod, "SolidMechanicsModelOptions") .def(py::init<_aka::AnalysisMethod>(), py::arg("analysis_method") = _aka::_explicit_lumped_mass); py::class_<_aka::Model>(mod, "Model") .def("setBaseName", &_aka::Model::setBaseName) .def("addDumpFieldVector", &_aka::Model::addDumpFieldVector) .def("addDumpField", &_aka::Model::addDumpField) .def("dump", &_aka::Model::dump); py::class_<_aka::NonLinearSolver>(mod, "NonLinearSolver") .def("set", [](_aka::NonLinearSolver & self, const std::string & id, const _aka::Real & val) { if (id == "max_iterations") self.set(id, int(val)); else if (id == "convergence_type") self.set(id, akantu::SolveConvergenceCriteria(_aka::UInt(val))); else self.set(id, val); }) .def("set", &_aka::NonLinearSolver::set<_aka::SolveConvergenceCriteria>); py::class_<_aka::ModelSolver>(mod, "ModelSolver") .def("getNonLinearSolver", (_aka::NonLinearSolver & (_aka::ModelSolver::*)(const _aka::ID &)) & _aka::ModelSolver::getNonLinearSolver, py::arg("solver_id") = "", py::return_value_policy::reference) .def("solveStep", &_aka::ModelSolver::solveStep, py::arg("solver_id") = ""); py::class_<_aka::SolidMechanicsModel, _aka::Model, _aka::ModelSolver>( mod, "SolidMechanicsModel") .def(py::init<_aka::Mesh &, _aka::UInt, const _aka::ID &, const _aka::MemoryID &, const _aka::ModelType>(), py::arg("mesh"), py::arg("spatial_dimension") = _aka::_all_dimensions, py::arg("id") = "solid_mechanics_model", py::arg("memory_id") = 0, py::arg("model_type") = _aka::ModelType::_solid_mechanics_model) .def("initFull", [](_aka::SolidMechanicsModel & self, const _aka::SolidMechanicsModelOptions & options) { self.initFull(options); }, py::arg("_analysis_method") = _aka::SolidMechanicsModelOptions()) .def("initFull", [](_aka::SolidMechanicsModel & self, const _aka::AnalysisMethod & _analysis_method) { self.initFull(_aka::SolidMechanicsModelOptions(_analysis_method)); }, py::arg("_analysis_method")) .def_deprecated("applyDirichletBC", "Deprecated: use applyBC") .def("applyBC", [](_aka::SolidMechanicsModel & self, _aka::BC::DirichletFunctor & func, const std::string & element_group) { self.applyBC(func, element_group); }) .def("applyBC", [](_aka::SolidMechanicsModel & self, _aka::BC::NeumannFunctor & func, const std::string & element_group) { self.applyBC(func, element_group); }) .def("setTimeStep", &_aka::SolidMechanicsModel::setTimeStep, py::arg("time_step"), py::arg("solver_id") = "") .def("getEnergy", py::overload_cast( &_aka::SolidMechanicsModel::getEnergy), py::arg("energy_id")) .def_function(assembleStiffnessMatrix) .def_function(assembleInternalForces) .def_function(getStableTimeStep) .def_function_nocopy(getExternalForce) .def_function_nocopy(getDisplacement) .def_function_nocopy(getPreviousDisplacement) .def_function_nocopy(getIncrement) .def_function_nocopy(getMass) .def_function_nocopy(getVelocity) .def_function_nocopy(getAcceleration) .def_function_nocopy(getInternalForce) .def_function_nocopy(getBlockedDOFs) - .def_function_nocopy(getIncrementFlag); + .def_function_nocopy(getIncrementFlag) + .def_function_nocopy(getMesh); - py::class_<_aka::ParameterRegistry>(mod, "ParameterRegistry") + py::class_<_aka::ParameterRegistry>(mod, "ParameterRegistry", + py::multiple_inheritance()) .def("registerParamReal", - [](_aka::ParameterRegistry & self, std::string name, - _aka::ParameterAccessType type, const std::string & description) { + [](_aka::ParameterRegistry & self, const std::string & name, + _aka::UInt type, const std::string & description) { _aka::Real * p = new _aka::Real; map_params[&self][name] = p; - self.registerParam<_aka::Real>(name, *p, type, description); + self.registerParam<_aka::Real>( + name, *p, _aka::ParameterAccessType(type), description); }) .def("registerParamReal", [](_aka::ParameterRegistry & self, const _aka::Real & _default, - std::string name, _aka::ParameterAccessType type, + const std::string & name, _aka::UInt type, const std::string & description) { _aka::Real * p = new _aka::Real; map_params[&self][name] = p; - self.registerParam<_aka::Real>(name, *p, _default, type, + self.registerParam<_aka::Real>(name, *p, _default, + _aka::ParameterAccessType(type), description); + }) + .def("getReal", + [](_aka::ParameterRegistry & self, const std::string & name) { + return _aka::Real(self.get(name)); }); - py::class_<_aka::Parsable, _aka::ParameterRegistry>(mod, "Parsable") + py::class_<_aka::Parsable, _aka::ParameterRegistry>( + mod, "Parsable", py::multiple_inheritance()) .def(py::init()); - py::class_<_aka::Material, _aka::PyMaterial, _aka::Parsable>(mod, "Material") - .def(py::init<_aka::SolidMechanicsModel &, const _aka::ID &>()); + py::class_<_aka::Material, _aka::PyMaterial, _aka::Parsable>( + mod, "Material", py::multiple_inheritance()) + .def(py::init<_aka::SolidMechanicsModel &, const _aka::ID &>()) + .def("getGradU", + [](_aka::Material & self, _aka::ElementType el_type, + _aka::GhostType ghost_type = _aka::_not_ghost) -> decltype(auto) { + return self.getGradU(el_type, ghost_type); + }, + py::return_value_policy::reference) + .def("getStress", + [](_aka::Material & self, _aka::ElementType el_type, + _aka::GhostType ghost_type = _aka::_not_ghost) -> decltype(auto) { + return self.getStress(el_type, ghost_type); + }, + py::return_value_policy::reference) + .def("initMaterial", &_aka::Material::initMaterial); py::class_<_aka::MaterialFactory>(mod, "MaterialFactory") .def_static("getInstance", []() -> _aka::MaterialFactory & { return _aka::Material::getFactory(); }, py::return_value_policy::reference) .def("registerAllocator", [](_aka::MaterialFactory & self, const std::string id, py::function func) { self.registerAllocator( id, [func, id](_aka::UInt dim, const _aka::ID &, _aka::SolidMechanicsModel & model, const _aka::ID & id) -> std::unique_ptr<_aka::Material> { py::object obj = func(dim, id, model, id); auto & ptr = py::cast<_aka::Material &>(obj); obj.release(); return std::unique_ptr<_aka::Material>(&ptr); }); }); return mod; } } // namespace