8#include <boost/python.hpp>
9#include <boost/python/def.hpp>
10#include <boost/python/numpy.hpp>
11namespace bp = boost::python;
12namespace np = boost::python::numpy;
73 MatrixDouble &coords, boost::shared_ptr<MatrixDouble> u_ptr,
74 boost::shared_ptr<MatrixDouble> stress_ptr,
75 boost::shared_ptr<MatrixDouble> strain_ptr,
76 boost::shared_ptr<VectorDouble> o_ptr,
bool symmetrize =
true);
93 MatrixDouble &coords, boost::shared_ptr<MatrixDouble> u_ptr,
94 boost::shared_ptr<MatrixDouble> stress_ptr,
95 boost::shared_ptr<MatrixDouble> strain_ptr,
96 boost::shared_ptr<MatrixDouble> o_ptr,
bool symmetrize =
true);
113 MatrixDouble &coords, boost::shared_ptr<MatrixDouble> u_ptr,
114 boost::shared_ptr<MatrixDouble> stress_ptr,
115 boost::shared_ptr<MatrixDouble> strain_ptr,
116 boost::shared_ptr<MatrixDouble> o_ptr,
bool symmetrize =
true);
133 MatrixDouble &coords, boost::shared_ptr<MatrixDouble> u_ptr,
134 boost::shared_ptr<MatrixDouble> stress_ptr,
135 boost::shared_ptr<MatrixDouble> strain_ptr,
136 boost::shared_ptr<MatrixDouble> o_ptr,
bool symmetrize =
true);
140 boost::shared_ptr<MatrixDouble> u_ptr,
141 boost::shared_ptr<MatrixDouble> t_ptr,
142 boost::shared_ptr<VectorDouble> o_ptr,
143 bool symmetrize =
true);
147 boost::shared_ptr<MatrixDouble> u_ptr,
148 boost::shared_ptr<MatrixDouble> t_ptr,
149 boost::shared_ptr<MatrixDouble> o_ptr);
153 boost::shared_ptr<MatrixDouble> u_ptr,
154 boost::shared_ptr<MatrixDouble> t_ptr,
155 boost::shared_ptr<MatrixDouble> o_ptr);
175 std::array<double, 3> ¢roid,
198 np::ndarray coords, np::ndarray u,
200 np::ndarray stress, np::ndarray strain, np::ndarray &o
219 np::ndarray coords, np::ndarray u,
221 np::ndarray stress, np::ndarray strain, np::ndarray &o
240 np::ndarray coords, np::ndarray u,
242 np::ndarray stress, np::ndarray strain, np::ndarray &o
262 np::ndarray coords, np::ndarray u,
264 np::ndarray stress, np::ndarray strain, np::ndarray &o
270 np::ndarray coords, np::ndarray u,
272 np::ndarray
t, np::ndarray &o
278 np::ndarray coords, np::ndarray u,
280 np::ndarray
t, np::ndarray &o
286 np::ndarray coords, np::ndarray u,
288 np::ndarray
t, np::ndarray &o
308 int block_id, np::ndarray coords, np::ndarray centroid, np::ndarray bbodx,
366boost::shared_ptr<ObjectiveFunctionData>
368 auto ptr = boost::make_shared<ObjectiveFunctionDataImpl>();
402 auto main_module = bp::import(
"__main__");
410 }
catch (bp::error_already_set
const &) {
423 auto t_f = getFTensor2FromMat<3, 3>(f);
424 auto t_s = getFTensor2SymmetricFromMat<SPACE_DIM>(s);
425 for (
int ii = 0; ii != s.size2(); ++ii) {
426 t_f(
i,
j) = t_s(
i,
j);
438 ptr + 0 * s.size2(), ptr + 1 * s.size2(),
439 ptr + 2 * s.size2(), ptr + 3 * s.size2(),
440 ptr + 4 * s.size2(), ptr + 5 * s.size2(),
441 ptr + 6 * s.size2(), ptr + 7 * s.size2(),
445 auto t_s = getFTensor2SymmetricFromMat<SPACE_DIM>(s);
446 for (
int ii = 0; ii != s.size2(); ++ii) {
447 t_s(
i,
j) = (t_f(
i,
j) || t_f(
j,
i)) / 2.0;
481 MatrixDouble &coords, boost::shared_ptr<MatrixDouble> u_ptr,
482 boost::shared_ptr<MatrixDouble> stress_ptr,
483 boost::shared_ptr<MatrixDouble> strain_ptr,
484 boost::shared_ptr<VectorDouble> o_ptr,
bool symmetrize) {
492 auto np_u =
convertToNumPy(u_ptr->data(), u_ptr->size1(), u_ptr->size2());
496 auto full_stress = symmetrize ?
copyToFull(*(stress_ptr)) : *(stress_ptr);
497 auto full_strain = symmetrize ?
copyToFull(*(strain_ptr)) : *(strain_ptr);
500 auto np_stress =
convertToNumPy(full_stress.data(), full_stress.size1(),
501 full_stress.size2());
502 auto np_strain =
convertToNumPy(full_strain.data(), full_strain.size1(),
503 full_strain.size2());
506 np::ndarray np_output = np::empty(bp::make_tuple(strain_ptr->size2()),
507 np::dtype::get_builtin<double>());
514 o_ptr->resize(stress_ptr->size2(),
false);
515 double *val_ptr =
reinterpret_cast<double *
>(np_output.get_data());
516 std::copy(val_ptr, val_ptr + strain_ptr->size2(), o_ptr->data().begin());
518 }
catch (bp::error_already_set
const &) {
557 MatrixDouble &coords, boost::shared_ptr<MatrixDouble> u_ptr,
558 boost::shared_ptr<MatrixDouble> stress_ptr,
559 boost::shared_ptr<MatrixDouble> strain_ptr,
560 boost::shared_ptr<MatrixDouble> o_ptr,
bool symmetrize) {
567 auto np_u =
convertToNumPy(u_ptr->data(), u_ptr->size1(), u_ptr->size2());
570 auto full_stress = symmetrize ?
copyToFull(*(stress_ptr)) : *(stress_ptr);
571 auto full_strain = symmetrize ?
copyToFull(*(strain_ptr)) : *(strain_ptr);
574 auto np_stress =
convertToNumPy(full_stress.data(), full_stress.size1(),
575 full_stress.size2());
576 auto np_strain =
convertToNumPy(full_strain.data(), full_strain.size1(),
577 full_strain.size2());
579 np::ndarray np_output =
580 np::empty(bp::make_tuple(full_strain.size1(), full_strain.size2()),
581 np::dtype::get_builtin<double>());
588 o_ptr->resize(stress_ptr->size1(), stress_ptr->size2(),
false);
589 double *val_ptr =
reinterpret_cast<double *
>(np_output.get_data());
593 }
catch (bp::error_already_set
const &) {
633 MatrixDouble &coords, boost::shared_ptr<MatrixDouble> u_ptr,
634 boost::shared_ptr<MatrixDouble> stress_ptr,
635 boost::shared_ptr<MatrixDouble> strain_ptr,
636 boost::shared_ptr<MatrixDouble> o_ptr,
bool symmetrize) {
643 auto np_u =
convertToNumPy(u_ptr->data(), u_ptr->size1(), u_ptr->size2());
646 auto full_stress = symmetrize ?
copyToFull(*(stress_ptr)) : *(stress_ptr);
647 auto full_strain = symmetrize ?
copyToFull(*(strain_ptr)) : *(strain_ptr);
649 auto np_stress =
convertToNumPy(full_stress.data(), full_stress.size1(),
650 full_stress.size2());
651 auto np_strain =
convertToNumPy(full_strain.data(), full_strain.size1(),
652 full_strain.size2());
655 np::ndarray np_output =
656 np::empty(bp::make_tuple(full_strain.size1(), full_strain.size2()),
657 np::dtype::get_builtin<double>());
662 o_ptr->resize(strain_ptr->size1(), strain_ptr->size2(),
false);
663 double *val_ptr =
reinterpret_cast<double *
>(np_output.get_data());
666 }
catch (bp::error_already_set
const &) {
708 MatrixDouble &coords, boost::shared_ptr<MatrixDouble> u_ptr,
709 boost::shared_ptr<MatrixDouble> stress_ptr,
710 boost::shared_ptr<MatrixDouble> strain_ptr,
711 boost::shared_ptr<MatrixDouble> o_ptr,
bool symmetrize) {
718 auto np_u =
convertToNumPy(u_ptr->data(), u_ptr->size1(), u_ptr->size2());
721 auto full_stress = symmetrize ?
copyToFull(*(stress_ptr)) : *(stress_ptr);
722 auto full_strain = symmetrize ?
copyToFull(*(strain_ptr)) : *(strain_ptr);
724 auto np_stress =
convertToNumPy(full_stress.data(), full_stress.size1(),
725 full_stress.size2());
726 auto np_strain =
convertToNumPy(full_strain.data(), full_strain.size1(),
727 full_strain.size2());
730 np::ndarray np_output =
731 np::empty(bp::make_tuple(u_ptr->size1(), u_ptr->size2()),
732 np::dtype::get_builtin<double>());
740 o_ptr->resize(u_ptr->size1(), u_ptr->size2(),
false);
741 double *val_ptr =
reinterpret_cast<double *
>(np_output.get_data());
742 std::copy(val_ptr, val_ptr + u_ptr->size1() * u_ptr->size2(),
743 o_ptr->data().begin());
745 }
catch (bp::error_already_set
const &) {
754 MatrixDouble &coords, boost::shared_ptr<MatrixDouble> u_ptr,
755 boost::shared_ptr<MatrixDouble> t_ptr,
756 boost::shared_ptr<MatrixDouble> o_ptr) {
762 auto np_u =
convertToNumPy(u_ptr->data(), u_ptr->size1(), u_ptr->size2());
763 auto np_t =
convertToNumPy(t_ptr->data(), t_ptr->size1(), t_ptr->size2());
765 np::ndarray np_output =
766 np::empty(bp::make_tuple(u_ptr->size1(), u_ptr->size2()),
767 np::dtype::get_builtin<double>());
771 o_ptr->resize(u_ptr->size1(), u_ptr->size2(),
false);
772 double *val_ptr =
reinterpret_cast<double *
>(np_output.get_data());
773 std::copy(val_ptr, val_ptr + u_ptr->size1() * u_ptr->size2(),
774 o_ptr->data().begin());
776 }
catch (bp::error_already_set
const &) {
784 MatrixDouble &coords, boost::shared_ptr<MatrixDouble> u_ptr,
785 boost::shared_ptr<MatrixDouble> t_ptr,
786 boost::shared_ptr<VectorDouble> o_ptr,
bool symmetrize) {
793 auto np_u =
convertToNumPy(u_ptr->data(), u_ptr->size1(), u_ptr->size2());
794 auto np_t =
convertToNumPy(t_ptr->data(), t_ptr->size1(), t_ptr->size2());
796 np::ndarray np_output = np::empty(bp::make_tuple(t_ptr->size2()),
797 np::dtype::get_builtin<double>());
801 o_ptr->resize(t_ptr->size2(),
false);
802 double *val_ptr =
reinterpret_cast<double *
>(np_output.get_data());
803 std::copy(val_ptr, val_ptr + t_ptr->size2(), o_ptr->data().begin());
805 }
catch (bp::error_already_set
const &) {
813 MatrixDouble &coords, boost::shared_ptr<MatrixDouble> u_ptr,
814 boost::shared_ptr<MatrixDouble> t_ptr,
815 boost::shared_ptr<MatrixDouble> o_ptr) {
820 auto np_u =
convertToNumPy(u_ptr->data(), u_ptr->size1(), u_ptr->size2());
821 auto np_t =
convertToNumPy(t_ptr->data(), t_ptr->size1(), t_ptr->size2());
823 np::ndarray np_output =
824 np::empty(bp::make_tuple(u_ptr->size1(), u_ptr->size2()),
825 np::dtype::get_builtin<double>());
829 o_ptr->resize(u_ptr->size1(), u_ptr->size2(),
false);
830 double *val_ptr =
reinterpret_cast<double *
>(np_output.get_data());
831 std::copy(val_ptr, val_ptr + u_ptr->size1() * u_ptr->size2(),
832 o_ptr->data().begin());
834 }
catch (bp::error_already_set
const &) {
877 int block_id,
MatrixDouble &coords, std::array<double, 3> ¢roid,
897 np::ndarray np_output =
898 np::empty(bp::make_tuple(coords.size1(), nb_modes, 3),
899 np::dtype::get_builtin<double>());
906 o_ptr.resize(nb_modes, coords.size1() * coords.size2(),
false);
907 double *val_ptr =
reinterpret_cast<double *
>(np_output.get_data());
909 std::copy(val_ptr, val_ptr + coords.size1() * coords.size2() * nb_modes,
910 o_ptr.data().begin());
912 }
catch (bp::error_already_set
const &) {
922 np::ndarray coords, np::ndarray u,
924 np::ndarray stress, np::ndarray strain, np::ndarray &o
930 if (bp::extract<bool>(
mainNamespace.attr(
"__contains__")(
"f"))) {
932 o = bp::extract<np::ndarray>(
934 }
else if (bp::extract<bool>(
936 o = bp::extract<np::ndarray>(
941 "Python function f_interior(coords,u,stress,strain) is not defined");
944 }
catch (bp::error_already_set
const &) {
954 np::ndarray coords, np::ndarray u,
956 np::ndarray stress, np::ndarray strain, np::ndarray &o
962 if (bp::extract<bool>(
mainNamespace.attr(
"__contains__")(
"f_stress"))) {
964 o = bp::extract<np::ndarray>(
966 }
else if (bp::extract<bool>(
968 o = bp::extract<np::ndarray>(
969 mainNamespace[
"f_interior_stress"](coords, u, stress, strain));
973 "Python function f_interior_stress(coords,u,stress,strain) is not defined");
976 }
catch (bp::error_already_set
const &) {
986 np::ndarray coords, np::ndarray u,
988 np::ndarray stress, np::ndarray strain, np::ndarray &o
994 if (bp::extract<bool>(
mainNamespace.attr(
"__contains__")(
"f_strain"))) {
996 o = bp::extract<np::ndarray>(
998 }
else if (bp::extract<bool>(
1000 o = bp::extract<np::ndarray>(
1001 mainNamespace[
"f_interior_strain"](coords, u, stress, strain));
1005 "Python function f_interior_strain(coords,u,stress,strain) is not defined");
1008 }
catch (bp::error_already_set
const &) {
1018 np::ndarray coords, np::ndarray u,
1020 np::ndarray stress, np::ndarray strain, np::ndarray &o
1026 if (bp::extract<bool>(
mainNamespace.attr(
"__contains__")(
"f_u"))) {
1028 o = bp::extract<np::ndarray>(
1030 }
else if (bp::extract<bool>(
1032 o = bp::extract<np::ndarray>(
1037 "Python function f_interior_u(coords,u,stress,strain) is not defined");
1040 }
catch (bp::error_already_set
const &) {
1050 np::ndarray coords, np::ndarray u,
1052 np::ndarray
t, np::ndarray &o
1058 if (bp::extract<bool>(
mainNamespace.attr(
"__contains__")(
"f_boundary_t"))) {
1059 o = bp::extract<np::ndarray>(
mainNamespace[
"f_boundary_t"](coords, u,
t));
1063 "Python function f_boundary_t(coords,u,t) is not defined");
1066 }
catch (bp::error_already_set
const &) {
1075 np::ndarray coords, np::ndarray u,
1077 np::ndarray
t, np::ndarray &o
1083 if (bp::extract<bool>(
mainNamespace.attr(
"__contains__")(
"f_boundary"))) {
1084 o = bp::extract<np::ndarray>(
mainNamespace[
"f_boundary"](coords, u,
t));
1085 }
else if (bp::extract<bool>(
1086 mainNamespace.attr(
"__contains__")(
"f_boundary_function"))) {
1087 o = bp::extract<np::ndarray>(
1092 "Python function f_boundary(coords,u,t) is not defined");
1095 }
catch (bp::error_already_set
const &) {
1104 np::ndarray coords, np::ndarray u,
1106 np::ndarray
t, np::ndarray &o
1112 if (bp::extract<bool>(
mainNamespace.attr(
"__contains__")(
"f_boundary_u"))) {
1113 o = bp::extract<np::ndarray>(
mainNamespace[
"f_boundary_u"](coords, u,
t));
1117 "Python function f_boundary_u(coords,u,t) is not defined");
1120 }
catch (bp::error_already_set
const &) {
1132 if (bp::extract<bool>(
1134 modes = bp::extract<int>(
mainNamespace[
"number_of_modes"](block_id));
1138 "Python function number_of_modes(block_id) is not defined");
1141 }
catch (bp::error_already_set
const &) {
1151 np::ndarray centroid,
1156 if (bp::extract<bool>(
mainNamespace.attr(
"__contains__")(
"block_modes"))) {
1157 o = bp::extract<np::ndarray>(
1158 mainNamespace[
"block_modes"](block_id, coords, centroid, bbodx));
1162 "Python function block_modes(block_id,coords,centroid,bbox) is not "
1165 }
catch (bp::error_already_set
const &) {
1196 auto dtype = np::dtype::get_builtin<double>();
1197 auto size = bp::make_tuple(rows, nb_gauss_pts);
1198 auto stride = bp::make_tuple(nb_gauss_pts *
sizeof(
double),
sizeof(
double));
1199 return (np::from_data(data.data(), dtype, size, stride, bp::object()));
1204 auto dtype = np::dtype::get_builtin<double>();
1205 auto size = bp::make_tuple(s);
1206 auto stride = bp::make_tuple(
sizeof(
double));
1207 return (np::from_data(ptr, dtype, size, stride, bp::object()));
Interface for Python-based objective function evaluation in topology optimization.
#define FTENSOR_INDEX(DIM, I)
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_OPERATION_UNSUCCESSFUL
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
FTensor::Index< 'i', SPACE_DIM > i
FTensor::Index< 'j', 3 > j
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
constexpr int SPACE_DIM
Space dimension of problem (2D or 3D), set at compile time.
boost::shared_ptr< ObjectiveFunctionData > create_python_objective_function(std::string py_file)
Factory function to create Python-integrated objective function interface.
constexpr double t
plate stiffness
Implementation of ObjectiveFunctionData interface using Python integration.
MoFEMErrorCode blockModesImpl(int block_id, np::ndarray coords, np::ndarray centroid, np::ndarray bbodx, np::ndarray &o_ptr)
Internal implementation for topology mode generation.
MoFEMErrorCode boundaryObjectiveFunctionImpl(np::ndarray coords, np::ndarray u, np::ndarray t, np::ndarray &o)
MoFEMErrorCode evalInteriorObjectiveFunction(MatrixDouble &coords, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > stress_ptr, boost::shared_ptr< MatrixDouble > strain_ptr, boost::shared_ptr< VectorDouble > o_ptr, bool symmetrize=true)
Evaluate objective function at current state.
virtual ~ObjectiveFunctionDataImpl()=default
MoFEMErrorCode evalBoundaryObjectiveGradientTraction(MatrixDouble &coords, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > t_ptr, boost::shared_ptr< MatrixDouble > o_ptr)
Evaluate gradient of objective function w.r.t. traction-like vector field.
MoFEMErrorCode boundaryObjectiveGradientUImpl(np::ndarray coords, np::ndarray u, np::ndarray t, np::ndarray &o)
bp::object mainNamespace
Main Python namespace for script execution.
MoFEMErrorCode interiorObjectiveGradientStrainImpl(np::ndarray coords, np::ndarray u, np::ndarray stress, np::ndarray strain, np::ndarray &o)
Internal implementation for strain gradient computation.
MoFEMErrorCode initPython(const std::string py_file)
Initialize Python interpreter and load objective function script.
MoFEMErrorCode interiorObjectiveFunctionImpl(np::ndarray coords, np::ndarray u, np::ndarray stress, np::ndarray strain, np::ndarray &o)
Internal implementation for objective function evaluation.
void copyToSymmetric(double *ptr, MatrixDouble &s)
Convert full matrix to symmetric tensor storage format.
MoFEMErrorCode evalInteriorObjectiveGradientStrain(MatrixDouble &coords, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > stress_ptr, boost::shared_ptr< MatrixDouble > strain_ptr, boost::shared_ptr< MatrixDouble > o_ptr, bool symmetrize=true)
Compute gradient of objective function with respect to strain.
MoFEMErrorCode blockModes(int block_id, MatrixDouble &coords, std::array< double, 3 > ¢roid, std::array< double, 6 > &bbodx, MatrixDouble &o_ptr)
Define spatial topology modes for design optimization.
MoFEMErrorCode evalBoundaryObjectiveFunction(MatrixDouble &coords, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > t_ptr, boost::shared_ptr< VectorDouble > o_ptr, bool symmetrize=true)
np::ndarray convertToNumPy(std::vector< double > &data, int rows, int nb_gauss_pts)
Convert std::vector to NumPy array for Python interface.
MatrixDouble copyToFull(MatrixDouble &s)
Convert symmetric tensor storage to full matrix format.
MoFEMErrorCode interiorObjectiveGradientUImpl(np::ndarray coords, np::ndarray u, np::ndarray stress, np::ndarray strain, np::ndarray &o)
Internal implementation for displacement gradient computation.
ObjectiveFunctionDataImpl()=default
MoFEMErrorCode numberOfModes(int block_id, int &modes)
Return number of topology optimization modes for given material block.
MoFEMErrorCode evalInteriorObjectiveGradientU(MatrixDouble &coords, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > stress_ptr, boost::shared_ptr< MatrixDouble > strain_ptr, boost::shared_ptr< MatrixDouble > o_ptr, bool symmetrize=true)
Compute gradient of objective function with respect to displacement.
MoFEMErrorCode interiorObjectiveGradientStressImpl(np::ndarray coords, np::ndarray u, np::ndarray stress, np::ndarray strain, np::ndarray &o)
Internal implementation for stress gradient computation.
MoFEMErrorCode evalInteriorObjectiveGradientStress(MatrixDouble &coords, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > stress_ptr, boost::shared_ptr< MatrixDouble > strain_ptr, boost::shared_ptr< MatrixDouble > o_ptr, bool symmetrize=true)
Compute gradient of objective function with respect to stress.
MoFEMErrorCode evalBoundaryObjectiveGradientU(MatrixDouble &coords, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > t_ptr, boost::shared_ptr< MatrixDouble > o_ptr)
MoFEMErrorCode boundaryObjectiveGradientTractionImpl(np::ndarray coords, np::ndarray u, np::ndarray t, np::ndarray &o)
Abstract interface for Python-defined objective functions.
#define EXECUTABLE_DIMENSION