Page MenuHomec4science

py_fe_engine.cc
No OneTemporary

File Metadata

Created
Mon, Feb 24, 02:29

py_fe_engine.cc

/**
* Copyright (©) 2019-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_aka_array.hh"
#include "py_aka_common.hh"
/* -------------------------------------------------------------------------- */
#include <element.hh>
#include <fe_engine.hh>
#include <fe_engine_basix.hh>
#include <integration_point.hh>
#include <integrator.hh>
/* -------------------------------------------------------------------------- */
#include <pybind11/functional.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
/* -------------------------------------------------------------------------- */
#include <memory>
/* -------------------------------------------------------------------------- */
namespace py = pybind11;
/* -------------------------------------------------------------------------- */
namespace akantu {
namespace {
class pyFEEngine : public FEEngineBasix {
public:
/* Inherit the constructors */
using Parent = FEEngineBasix;
using FEEngineBasix::FEEngineBasix;
void initShapeFunctions(GhostType ghost_type = _not_ghost) override {
PYBIND11_OVERRIDE(void, Parent, initShapeFunctions, ghost_type);
};
void integrate(const ElementTypeMapArray<Real> & f,
ElementTypeMapArray<Real> & intf,
const ElementTypeMapArray<Idx> * filter_elements =
nullptr) const override {
PYBIND11_OVERRIDE(void, Parent, integrate, f, intf, filter_elements);
}
void integrate(
const Array<Real> & f, Array<Real> & intf, Int nb_degree_of_freedom,
ElementType type, GhostType ghost_type = _not_ghost,
const Array<Idx> & filter_elements = empty_filter) const override {
PYBIND11_OVERRIDE(void, Parent, integrate, f, intf, nb_degree_of_freedom,
type, ghost_type, filter_elements);
}
/// integrate a scalar value on all elements of type "type"
[[nodiscard]] Real integrate(
const Array<Real> & f, ElementType type,
GhostType ghost_type = _not_ghost,
const Array<Idx> & filter_elements = empty_filter) const override {
PYBIND11_OVERRIDE(Real, Parent, integrate, f, type, ghost_type,
filter_elements);
}
/// integrate one element scalar value on all elements of type "type"
[[nodiscard]] Real
integrate(const Ref<const VectorXr> f, ElementType type, Int index,
GhostType ghost_type = _not_ghost) const override {
PYBIND11_OVERRIDE(Real, Parent, integrate, f, type, index, ghost_type);
}
/// interpolate on a physical point inside an element
void interpolate(const Ref<const VectorXr> real_coords,
const Ref<const MatrixXr> nodal_values,
Ref<VectorXr> interpolated,
const Element & element) const override {
PYBIND11_OVERRIDE(void, Parent, interpolate, real_coords, nodal_values,
interpolated, element);
}
/// get the number of integration points
[[nodiscard]] Int
getNbIntegrationPoints(ElementType type,
GhostType ghost_type = _not_ghost) const override {
PYBIND11_OVERRIDE(Int, Parent, getNbIntegrationPoints, type, ghost_type);
}
/// get shapes pre-computed
[[nodiscard]] const Array<Real> &
getShapes(ElementType type, GhostType ghost_type = _not_ghost,
Int id = 0) const override {
PYBIND11_OVERRIDE(const Array<Real> &, Parent, getShapes, type,
ghost_type, id);
}
/// get the derivatives of shapes
[[nodiscard]] const Array<Real> &
getShapesDerivatives(ElementType type, GhostType ghost_type = _not_ghost,
Int id = 0) const override {
PYBIND11_OVERRIDE(const Array<Real> &, Parent, getShapesDerivatives, type,
ghost_type, id);
}
/// get integration points
[[nodiscard]] inline const Matrix<Real> &
getIntegrationPoints(ElementType type,
GhostType ghost_type = _not_ghost) const override {
PYBIND11_OVERRIDE(Matrix<Real> &, Parent, getIntegrationPoints, type,
ghost_type);
}
/* ------------------------------------------------------------------------
*/
/* Shape method bridges */
/* ------------------------------------------------------------------------
*/
/// compute the gradient of a nodal field on the integration points
void gradientOnIntegrationPoints(
const Array<Real> & u, Array<Real> & nablauq, Int nb_degree_of_freedom,
ElementType type, GhostType ghost_type = _not_ghost,
const Array<Idx> & filter_elements = empty_filter) const override {
PYBIND11_OVERRIDE(void, Parent, gradientOnIntegrationPoints, u, nablauq,
nb_degree_of_freedom, type, ghost_type,
filter_elements);
}
/// interpolate a nodal field on the integration points
void interpolateOnIntegrationPoints(
const Array<Real> & u, Array<Real> & uq, Int nb_degree_of_freedom,
ElementType type, GhostType ghost_type = _not_ghost,
const Array<Idx> & filter_elements = empty_filter) const override {
PYBIND11_OVERRIDE(void, Parent, interpolateOnIntegrationPoints, u, uq,
nb_degree_of_freedom, type, ghost_type,
filter_elements);
}
/// interpolate a nodal field on the integration points given a
/// by_element_type
void interpolateOnIntegrationPoints(
const Array<Real> & u, ElementTypeMapArray<Real> & uq,
const ElementTypeMapArray<Idx> * filter_elements =
nullptr) const override {
PYBIND11_OVERRIDE(void, Parent, interpolateOnIntegrationPoints, u, uq,
filter_elements);
}
/// pre multiplies a tensor by the shapes derivaties
void computeBtD(
const Array<Real> & Ds, Array<Real> & BtDs, ElementType type,
GhostType ghost_type,
const Array<Idx> & filter_elements = empty_filter) const override {
PYBIND11_OVERRIDE(void, Parent, computeBtD, Ds, BtDs, type, ghost_type,
filter_elements);
}
/// left and right multiplies a tensor by the shapes derivaties
void computeBtDB(
const Array<Real> & Ds, Array<Real> & BtDBs, Int order_d,
ElementType type, GhostType ghost_type,
const Array<Idx> & filter_elements = empty_filter) const override {
PYBIND11_OVERRIDE(void, Parent, computeBtDB, Ds, BtDBs, order_d, type,
ghost_type, filter_elements);
}
/// left multiples a vector by the shape functions
void computeNtb(const Array<Real> & bs, Array<Real> & Ntbs,
ElementType type, GhostType ghost_type,
const Array<Idx> & filter_elements) const override {
PYBIND11_OVERRIDE(void, Parent, computeNtb, bs, Ntbs, type, ghost_type,
filter_elements);
}
/// left and right multiplies a tensor by the shapes
void computeNtbN(
const Array<Real> & bs, Array<Real> & NtbNs, ElementType type,
GhostType ghost_type,
const Array<Idx> & filter_elements = empty_filter) const override {
PYBIND11_OVERRIDE(void, Parent, computeNtbN, bs, NtbNs, type, ghost_type,
filter_elements);
}
/// compute the position of integration points given by an element_type_map
/// from nodes position
inline void computeIntegrationPointsCoordinates(
ElementTypeMapArray<Real> & quadrature_points_coordinates,
const ElementTypeMapArray<Idx> * filter_elements =
nullptr) const override {
PYBIND11_OVERRIDE(void, Parent, computeIntegrationPointsCoordinates,
quadrature_points_coordinates, filter_elements);
}
/// compute the position of integration points from nodes position
inline void computeIntegrationPointsCoordinates(
Array<Real> & quadrature_points_coordinates, ElementType type,
GhostType ghost_type = _not_ghost,
const Array<Idx> & filter_elements = empty_filter) const override {
PYBIND11_OVERRIDE(void, Parent, computeIntegrationPointsCoordinates,
quadrature_points_coordinates, type, ghost_type,
filter_elements);
}
/// interpolate field at given position (interpolation_points) from given
/// values of this field at integration points (field)
inline void interpolateElementalFieldFromIntegrationPoints(
const ElementTypeMapArray<Real> & field,
const ElementTypeMapArray<Real> & interpolation_points_coordinates,
ElementTypeMapArray<Real> & result, GhostType ghost_type,
const ElementTypeMapArray<Idx> * element_filter) const override {
PYBIND11_OVERRIDE(
void, Parent, interpolateElementalFieldFromIntegrationPoints, field,
interpolation_points_coordinates, result, ghost_type, element_filter);
}
/// Interpolate field at given position from given values of this field at
/// integration points (field)
/// using matrices precomputed with
/// initElementalFieldInterplationFromIntegrationPoints
inline void interpolateElementalFieldFromIntegrationPoints(
const ElementTypeMapArray<Real> & field,
const ElementTypeMapArray<Real> &
interpolation_points_coordinates_matrices,
const ElementTypeMapArray<Real> & quad_points_coordinates_inv_matrices,
ElementTypeMapArray<Real> & result, GhostType ghost_type,
const ElementTypeMapArray<Idx> * element_filter) const override {
PYBIND11_OVERRIDE(void, Parent,
interpolateElementalFieldFromIntegrationPoints, field,
interpolation_points_coordinates_matrices,
quad_points_coordinates_inv_matrices, result,
ghost_type, element_filter);
}
/// Build pre-computed matrices for interpolation of field form integration
/// points at other given positions (interpolation_points)
inline void initElementalFieldInterpolationFromIntegrationPoints(
const ElementTypeMapArray<Real> & interpolation_points_coordinates,
ElementTypeMapArray<Real> & interpolation_points_coordinates_matrices,
ElementTypeMapArray<Real> & quad_points_coordinates_inv_matrices,
const ElementTypeMapArray<Idx> * element_filter =
nullptr) const override {
PYBIND11_OVERRIDE(void, Parent,
initElementalFieldInterpolationFromIntegrationPoints,
interpolation_points_coordinates,
interpolation_points_coordinates_matrices,
quad_points_coordinates_inv_matrices, element_filter);
}
/// compute the shape on a provided point
void computeShapes(const Ref<const VectorXr> real_coords, Int element,
ElementType type, Ref<VectorXr> shapes,
GhostType ghost_type = _not_ghost) const override {
PYBIND11_OVERRIDE(void, Parent, computeShapes, real_coords, element, type,
shapes, ghost_type);
}
void
computeShapeDerivatives(const Ref<const VectorXr> real_coords, Int element,
ElementType type, Ref<MatrixXr> shape_derivatives,
GhostType ghost_type = _not_ghost) const override {
PYBIND11_OVERRIDE(void, Parent, computeShapeDerivatives, real_coords,
element, type, shape_derivatives, ghost_type);
}
void computeNormalsOnIntegrationPoints(
GhostType ghost_type = _not_ghost) override {
PYBIND11_OVERRIDE(void, Parent, computeNormalsOnIntegrationPoints,
ghost_type);
}
void computeNormalsOnIntegrationPoints(
const Array<Real> & field, GhostType ghost_type = _not_ghost) override {
PYBIND11_OVERRIDE(void, Parent, computeNormalsOnIntegrationPoints, field,
ghost_type);
}
void computeNormalsOnIntegrationPoints(
const Array<Real> & field, Array<Real> & normal, ElementType type,
GhostType ghost_type = _not_ghost) const override {
PYBIND11_OVERRIDE(void, Parent, computeNormalsOnIntegrationPoints, field,
normal, type, ghost_type);
}
void assembleFieldLumped(
const std::function<void(Matrix<Real> &, const Element &)> &
field_funct,
const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager,
ElementType type, GhostType ghost_type) const override {
PYBIND11_OVERRIDE(void, Parent, assembleFieldLumped, field_funct,
matrix_id, dof_id, dof_manager, type, ghost_type);
}
/// assemble a field as a matrix (ex. rho to mass matrix)
void assembleFieldMatrix(
const std::function<void(Matrix<Real> &, const Element &)> &
field_funct,
const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager,
ElementType type, GhostType ghost_type) const override {
PYBIND11_OVERRIDE(void, Parent, assembleFieldMatrix, field_funct,
matrix_id, dof_id, dof_manager, type, ghost_type);
}
void onElementsAdded(const Array<Element> & new_elements,
const NewElementsEvent & unused) override {
PYBIND11_OVERRIDE(void, Parent, onElementsAdded, new_elements, unused);
}
void onElementsRemoved(const Array<Element> & unused,
const ElementTypeMapArray<Idx> & unused2,
const RemovedElementsEvent & unused3) override {
PYBIND11_OVERRIDE(void, Parent, onElementsRemoved, unused, unused2,
unused3);
}
void onElementsChanged(const Array<Element> & unused,
const Array<Element> & unused2,
const ElementTypeMapArray<Idx> & unused3,
const ChangedElementsEvent & unused4) override {
PYBIND11_OVERRIDE(void, Parent, onElementsChanged, unused, unused2,
unused3, unused4);
}
/// get the shape class (probably useless: see getShapeFunction)
[[nodiscard]] const ShapeFunctions &
getShapeFunctionsInterface() const override {
PYBIND11_OVERRIDE(const ShapeFunctions &, Parent,
getShapeFunctionsInterface);
}
/// get the integrator class (probably useless: see getIntegrator)
[[nodiscard]] const Integrator & getIntegratorInterface() const override {
PYBIND11_OVERRIDE(const Integrator &, Parent, getIntegratorInterface);
}
};
/* ------------------------------------------------------------------------ */
} // namespace
} // namespace akantu
namespace akantu {
void register_fe_engine(py::module & mod) {
py::class_<Element>(mod, "Element")
.def(py::init([](ElementType type, Int id, GhostType ghost_type) {
return std::make_unique<Element>(Element{type, id, ghost_type});
}),
py::arg("type"), py::arg("ghost_type"),
py::arg("ghost_type") = _not_ghost)
.def("__lt__",
[](Element & self, const Element & other) { return (self < other); })
.def("__repr__", [](Element & self) { return std::to_string(self); });
mod.attr("ElementNull") = ElementNull;
py::class_<FEEngine, std::shared_ptr<FEEngine>>(mod, "FEEngine")
.def(
"getNbIntegrationPoints",
[](FEEngine & fem, ElementType type, GhostType ghost_type) {
return fem.getNbIntegrationPoints(type, ghost_type);
},
py::arg("type"), py::arg("ghost_type") = _not_ghost)
.def("initShapeFunctions", &FEEngine::initShapeFunctions,
py::arg("ghost_type") = _not_ghost)
.def(
"integrate",
[](FEEngine & self,
const std::shared_ptr<ElementTypeMapArray<Real>> f,
std::shared_ptr<ElementTypeMapArray<Real>> intf,
std::shared_ptr<const ElementTypeMapArray<Idx>> filter_elements) {
self.integrate(*f, *intf, filter_elements.get());
},
py::arg("f"), py::arg("intf"), py::arg("filter_elements") = nullptr)
.def(
"integrate",
[](FEEngine & self, const Array<Real> & f, Array<Real> & intf,
Int nb_degree_of_freedom, ElementType type,
GhostType ghost_type = _not_ghost,
const Array<Idx> & filter_elements = empty_filter) {
// Check to overcome the empty_filter that is maped as a numpy
// array without an id
if (filter_elements.data() == empty_filter.data()) {
self.integrate(f, intf, nb_degree_of_freedom, type, ghost_type,
empty_filter);
} else {
self.integrate(f, intf, nb_degree_of_freedom, type, ghost_type,
filter_elements);
}
},
py::arg("f"), py::arg("intf"), py::arg("nb_degree_of_freedom"),
py::arg("type"), py::arg("ghost_type") = _not_ghost,
py::arg("filter_elements") = empty_filter)
.def(
"integrate",
[](FEEngine & self, const Array<Real> & f, ElementType type,
GhostType ghost_type = _not_ghost,
const Array<Idx> & filter_elements = empty_filter) -> Real {
// Check to overcome the empty_filter that is maped as a numpy
// array without an id
if (filter_elements.data() == empty_filter.data()) {
return self.integrate(f, type, ghost_type, empty_filter);
} else {
return self.integrate(f, type, ghost_type, filter_elements);
}
},
py::arg("f"), py::arg("type"), py::arg("ghost_type") = _not_ghost,
py::arg("filter_elements") = empty_filter)
.def(
"gradientOnIntegrationPoints",
[](FEEngine & fem, const Array<Real> & u, Array<Real> & nablauq,
const Int nb_degree_of_freedom, ElementType type,
GhostType ghost_type, const Array<Idx> & filter_elements) {
// Check to overcome the empty_filter that is maped as a numpy
// array without an id
if (filter_elements.data() == empty_filter.data()) {
fem.gradientOnIntegrationPoints(u, nablauq, nb_degree_of_freedom,
type, ghost_type, empty_filter);
} else {
fem.gradientOnIntegrationPoints(u, nablauq, nb_degree_of_freedom,
type, ghost_type,
filter_elements);
}
},
py::arg("u"), py::arg("nablauq"), py::arg("nb_degree_of_freedom"),
py::arg("type"), py::arg("ghost_type") = _not_ghost,
py::arg("filter_elements") = empty_filter)
.def(
"interpolateOnIntegrationPoints",
[](FEEngine & self, const Array<Real> & u, Array<Real> & uq,
Int nb_degree_of_freedom, ElementType type, GhostType ghost_type,
const Array<Idx> & filter_elements) {
// Check to overcome the empty_filter that is maped as a numpy
// array without an id
if (filter_elements.data() == empty_filter.data()) {
self.interpolateOnIntegrationPoints(
u, uq, nb_degree_of_freedom, type, ghost_type, empty_filter);
} else {
self.interpolateOnIntegrationPoints(u, uq, nb_degree_of_freedom,
type, ghost_type,
filter_elements);
}
},
py::arg("u"), py::arg("uq"), py::arg("nb_degree_of_freedom"),
py::arg("type"), py::arg("ghost_type") = _not_ghost,
py::arg("filter_elements") = empty_filter)
.def(
"interpolateOnIntegrationPoints",
[](FEEngine & self, const Array<Real> & u,
std::shared_ptr<ElementTypeMapArray<Real>> uq,
std::shared_ptr<const ElementTypeMapArray<Idx>> filter_elements) {
self.interpolateOnIntegrationPoints(u, *uq, filter_elements.get());
},
py::arg("u"), py::arg("uq"), py::arg("filter_elements") = nullptr)
.def(
"computeBtD",
[](FEEngine & self, const Array<Real> & Ds, Array<Real> & BtDs,
ElementType type, GhostType ghost_type = _not_ghost,
const Array<Idx> & filter_elements = empty_filter) {
// Check to overcome the empty_filter that is maped as a numpy
// array without an id
if (filter_elements.data() == empty_filter.data()) {
self.computeBtD(Ds, BtDs, type, ghost_type, empty_filter);
} else {
self.computeBtD(Ds, BtDs, type, ghost_type, filter_elements);
}
},
py::arg("Ds"), py::arg("BtDs"), py::arg("type"),
py::arg("ghost_type") = _not_ghost,
py::arg("filter_elements") = empty_filter)
.def(
"computeBtDB",
[](FEEngine & self, const Array<Real> & Ds, Array<Real> & BtDBs,
Int order_d, ElementType type, GhostType ghost_type = _not_ghost,
const Array<Idx> & filter_elements = empty_filter) {
// Check to overcome the empty_filter that is maped as a numpy
// array without an id
if (filter_elements.data() == empty_filter.data()) {
self.computeBtDB(Ds, BtDBs, order_d, type, ghost_type,
empty_filter);
} else {
self.computeBtDB(Ds, BtDBs, order_d, type, ghost_type,
filter_elements);
}
},
py::arg("Ds"), py::arg("BtDBs"), py::arg("order_d"), py::arg("type"),
py::arg("ghost_type") = _not_ghost,
py::arg("filter_elements") = empty_filter)
.def(
"computeNtb",
[](FEEngine & self, const Array<Real> & bs, Array<Real> & Ntbs,
ElementType type, GhostType ghost_type = _not_ghost,
const Array<Idx> & filter_elements = empty_filter) {
// Check to overcome the empty_filter that is maped as a numpy
// array without an id
if (filter_elements.data() == empty_filter.data()) {
self.computeNtb(bs, Ntbs, type, ghost_type, empty_filter);
} else {
self.computeNtb(bs, Ntbs, type, ghost_type, filter_elements);
}
},
py::arg("bs"), py::arg("Ntbs"), py::arg("type"),
py::arg("ghost_type") = _not_ghost,
py::arg("filter_elements") = empty_filter)
.def(
"computeNtbN",
[](FEEngine & self, const Array<Real> & bs, Array<Real> & NtbNs,
ElementType type, GhostType ghost_type = _not_ghost,
const Array<Idx> & filter_elements = empty_filter) {
// Check to overcome the empty_filter that is maped as a numpy
// array without an id
if (filter_elements.data() == empty_filter.data()) {
self.computeNtbN(bs, NtbNs, type, ghost_type, empty_filter);
} else {
self.computeNtbN(bs, NtbNs, type, ghost_type, filter_elements);
}
},
py::arg("bs"), py::arg("NtbNs"), py::arg("type"),
py::arg("ghost_type") = _not_ghost,
py::arg("filter_elements") = empty_filter)
.def(
"computeIntegrationPointsCoordinates",
[](FEEngine & self,
std::shared_ptr<ElementTypeMapArray<Real>> coordinates,
std::shared_ptr<const ElementTypeMapArray<Idx>> filter_elements)
-> decltype(auto) {
return self.computeIntegrationPointsCoordinates(
*coordinates, filter_elements.get());
},
py::arg("coordinates"), py::arg("filter_elements") = nullptr)
.def(
"assembleFieldLumped",
[](FEEngine & fem,
const std::function<void(Matrix<Real> &, const Element &)> &
field_funct,
const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager,
ElementType type, GhostType ghost_type) {
fem.assembleFieldLumped(field_funct, matrix_id, dof_id, dof_manager,
type, ghost_type);
},
py::arg("field_funct"), py::arg("matrix_id"), py::arg("dof_id"),
py::arg("dof_manager"), py::arg("type"),
py::arg("ghost_type") = _not_ghost)
.def(
"assembleFieldMatrix",
[](FEEngine & fem,
const std::function<void(Matrix<Real> &, const Element &)> &
field_funct,
const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager,
ElementType type, GhostType ghost_type = _not_ghost) {
fem.assembleFieldMatrix(field_funct, matrix_id, dof_id, dof_manager,
type, ghost_type);
},
py::arg("field_funct"), py::arg("matrix_id"), py::arg("dof_id"),
py::arg("dof_manager"), py::arg("type"),
py::arg("ghost_type") = _not_ghost)
.def("getElementInradius",
[](FEEngine & self, const Element & element) {
return self.getElementInradius(element);
})
.def("getNormalsOnIntegrationPoints",
&FEEngine::getNormalsOnIntegrationPoints, py::arg("type"),
py::arg("ghost_type") = _not_ghost,
py::return_value_policy::reference)
.def("getShapes", &FEEngine::getShapes, py::arg("type"),
py::arg("ghost_type") = _not_ghost, py::arg("id") = 0,
py::return_value_policy::reference)
.def("getShapesDerivatives", &FEEngine::getShapesDerivatives,
py::arg("type"), py::arg("ghost_type") = _not_ghost,
py::arg("id") = 0, py::return_value_policy::reference)
.def(
"getMesh", [](FEEngine & fem) -> Mesh & { return fem.getMesh(); },
py::return_value_policy::reference);
py::class_<IntegrationPoint>(mod, "IntegrationPoint");
py::class_<FEEngineBasix, pyFEEngine, FEEngine,
std::shared_ptr<FEEngineBasix>>(mod, "FEEngineBasix")
.def(py::init<Mesh &, Int, const ID &, bool>(), py::arg("mesh"),
py::arg("spatial_dimension"), py::arg("id") = "fem",
py::arg("do_not_precompute") = false);
}
} // namespace akantu

Event Timeline