v0.16.3
Loading...
Searching...
No Matches
Public Member Functions | Private Member Functions | Private Attributes | List of all members
ShapeOptimization::ObjectiveFunctionDataImpl Struct Reference

Implementation of ObjectiveFunctionData interface using Python integration. More...

Inheritance diagram for ShapeOptimization::ObjectiveFunctionDataImpl:
[legend]
Collaboration diagram for ShapeOptimization::ObjectiveFunctionDataImpl:
[legend]

Public Member Functions

 ObjectiveFunctionDataImpl ()=default
 
virtual ~ObjectiveFunctionDataImpl ()=default
 
MoFEMErrorCode initPython (const std::string py_file)
 Initialize Python interpreter and load objective function script.
 
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< MatrixDouble > o_ptr, bool symmetrize=true)
 Evaluate objective function at current state.
 
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 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 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 evalBoundaryObjectiveFunction (MatrixDouble &coords, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > t_ptr, boost::shared_ptr< VectorDouble > o_ptr, bool symmetrize=true)
 
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 evalBoundaryObjectiveGradientU (MatrixDouble &coords, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > t_ptr, boost::shared_ptr< MatrixDouble > o_ptr)
 
MoFEMErrorCode numberOfModes (int block_id, int &modes)
 Return number of topology optimization modes for given material block.
 
MoFEMErrorCode blockModes (int block_id, MatrixDouble &coords, std::array< double, 3 > &centroid, std::array< double, 6 > &bbodx, MatrixDouble &o_ptr)
 Define spatial topology modes for design optimization.
 
- Public Member Functions inherited from ShapeOptimization::ObjectiveFunctionData
virtual ~ObjectiveFunctionData ()=default
 

Private Member Functions

MoFEMErrorCode interiorObjectiveFunctionImpl (np::ndarray coords, np::ndarray u, np::ndarray stress, np::ndarray strain, np::ndarray &o)
 Internal implementation for objective function evaluation.
 
MoFEMErrorCode interiorObjectiveGradientStressImpl (np::ndarray coords, np::ndarray u, np::ndarray stress, np::ndarray strain, np::ndarray &o)
 Internal implementation for stress gradient computation.
 
MoFEMErrorCode interiorObjectiveGradientStrainImpl (np::ndarray coords, np::ndarray u, np::ndarray stress, np::ndarray strain, np::ndarray &o)
 Internal implementation for strain gradient computation.
 
MoFEMErrorCode interiorObjectiveGradientUImpl (np::ndarray coords, np::ndarray u, np::ndarray stress, np::ndarray strain, np::ndarray &o)
 Internal implementation for displacement gradient computation.
 
MoFEMErrorCode boundaryObjectiveGradientTractionImpl (np::ndarray coords, np::ndarray u, np::ndarray t, np::ndarray &o)
 
MoFEMErrorCode boundaryObjectiveFunctionImpl (np::ndarray coords, np::ndarray u, np::ndarray t, np::ndarray &o)
 
MoFEMErrorCode boundaryObjectiveGradientUImpl (np::ndarray coords, np::ndarray u, np::ndarray t, np::ndarray &o)
 
MoFEMErrorCode blockModesImpl (int block_id, np::ndarray coords, np::ndarray centroid, np::ndarray bbodx, np::ndarray &o_ptr)
 Internal implementation for topology mode generation.
 
np::ndarray convertToNumPy (std::vector< double > &data, int rows, int nb_gauss_pts)
 Convert std::vector to NumPy array for Python interface.
 
np::ndarray convertToNumPy (double *ptr, int s)
 Convert raw pointer to NumPy array for Python interface.
 
MatrixDouble copyToFull (MatrixDouble &s)
 Convert symmetric tensor storage to full matrix format.
 
void copyToSymmetric (double *ptr, MatrixDouble &s)
 Convert full matrix to symmetric tensor storage format.
 

Private Attributes

bp::object mainNamespace
 Main Python namespace for script execution.
 

Detailed Description

Implementation of ObjectiveFunctionData interface using Python integration.

This class provides a concrete implementation of the ObjectiveFunctionData interface that bridges MoFEM C++ data structures with Python-defined objective functions. It enables flexible definition of optimization objectives through Python scripting while maintaining high-performance computation in the C++ finite element framework.

Key features:

The class handles:

  1. Loading and executing Python objective function scripts
  2. Converting MoFEM data structures to NumPy arrays
  3. Calling Python functions for objective evaluation
  4. Converting Python results back to MoFEM format
  5. Managing Python interpreter state and namespace

Example Python interface functions that must be defined:

Definition at line 51 of file ObjectiveFunctionData.cpp.

Constructor & Destructor Documentation

◆ ObjectiveFunctionDataImpl()

ShapeOptimization::ObjectiveFunctionDataImpl::ObjectiveFunctionDataImpl ( )
default

◆ ~ObjectiveFunctionDataImpl()

virtual ShapeOptimization::ObjectiveFunctionDataImpl::~ObjectiveFunctionDataImpl ( )
virtualdefault

Member Function Documentation

◆ blockModes()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::blockModes ( int  block_id,
MatrixDouble &  coords,
std::array< double, 3 > &  centroid,
std::array< double, 6 > &  bbodx,
MatrixDouble &  o_ptr 
)
virtual

Define spatial topology modes for design optimization.

Generate spatial topology modes for design optimization.

Generates basis functions that define how the geometry can be modified during topology optimization. These modes serve as design variables and define the design space for optimization.

Parameters
block_idMaterial block identifier
coordsElement coordinates
centroidBlock centroid coordinates
bbodxBounding box dimensions [xmin,xmax,ymin,ymax,zmin,zmax]
o_ptrOutput mode vectors
Returns
MoFEMErrorCode Success or error code

This method defines the design parameterization for topology optimization by generating spatial basis functions (modes) that describe how the geometry can be modified during optimization. These modes serve as design variables and define the feasible design space for the optimization problem.

Mathematical context: The geometry modification is parameterized as: x_new = x_original + Σ(αᵢ * φᵢ(x)) where αᵢ are design variables and φᵢ(x) are spatial mode functions

Common mode types:

  • Radial basis functions: φ(x) = exp(-||x-c||²/σ²) for localized changes
  • Polynomial modes: φ(x) = xⁿyᵐzᵖ for global shape changes
  • Sinusoidal modes: φ(x) = sin(kx)cos(ly) for periodic patterns
  • Principal component modes: Derived from geometric sensitivity analysis

Process:

  1. Query Python function for number of modes for this material block
  2. Convert coordinate data and geometric information to NumPy format
  3. Call Python function block_modes(block_id, coords, centroid, bbox)
  4. Python returns mode vectors for each coordinate at each mode
  5. Reshape and store modes for use as design variables in optimization

The modes enable efficient design space exploration and gradient-based optimization while maintaining geometric feasibility and smoothness.

Parameters
block_idMaterial block identifier for mode generation
coordsElement coordinates where modes are evaluated
centroidGeometric centroid of the material block [x,y,z]
bbodxBounding box dimensions [xmin,xmax,ymin,ymax,zmin,zmax]
o_ptrOutput matrix: modes × (coordinates × spatial_dimension)
Returns
MoFEMErrorCode Success or error code

Implements ShapeOptimization::ObjectiveFunctionData.

Definition at line 967 of file ObjectiveFunctionData.cpp.

969 {
971 try {
972
973 // Query Python function for number of topology modes for this block
974 int nb_modes;
975 CHKERR numberOfModes(block_id, nb_modes);
976
977 // Convert coordinate matrix to NumPy format for Python processing
978 auto np_coords =
979 convertToNumPy(coords.data(), coords.size1(), coords.size2());
980
981 // Convert geometric information to NumPy arrays
982 auto np_centroid =
983 convertToNumPy(centroid.data(), 3); // Block centroid [x,y,z]
984 auto np_bbodx = convertToNumPy(
985 bbodx.data(), 6); // Bounding box [xmin,xmax,ymin,ymax,zmin,zmax]
986
987 // Prepare output array: [modes × (coordinates * spatial_dimensions)]
988 np::ndarray np_output =
989 np::empty(bp::make_tuple(nb_modes, coords.size1(), coords.size2()),
990 np::dtype::get_builtin<double>());
991
992 // Call Python implementation to generate topology modes
993 CHKERR blockModesImpl(block_id, np_coords, np_centroid, np_bbodx,
994 np_output);
995
996 // Check the shape of returned array
997 if (np_output.get_shape()[0] != nb_modes ||
998 np_output.get_shape()[1] != coords.size1() ||
999 np_output.get_shape()[2] != coords.size2()) {
1001 "Wrong shape of Modes from python expected (" +
1002 std::to_string(nb_modes) + ", " +
1003 std::to_string(coords.size1()) + ", " +
1004 std::to_string(coords.size2()) + "), got (" +
1005 std::to_string(np_output.get_shape()[0]) + ", " +
1006 std::to_string(np_output.get_shape()[1]) + ", " +
1007 std::to_string(np_output.get_shape()[2]) + ")");
1008 }
1009
1010 // Reshape output matrix for MoFEM format: [modes × (coordinates * spatial_dimensions)]
1011 o_ptr.resize(nb_modes, coords.size1() * coords.size2(), false);
1012 double *val_ptr = reinterpret_cast<double *>(np_output.get_data());
1013 // Copy flattened mode data to output matrix
1014 std::copy(val_ptr, val_ptr + coords.size1() * coords.size2() * nb_modes,
1015 o_ptr.data().begin());
1016
1017 } catch (bp::error_already_set const &) {
1018 // Handle Python errors in mode generation
1019 PyErr_Print();
1021 }
1023}
#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
Definition definitions.h:34
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
MoFEMErrorCode blockModesImpl(int block_id, np::ndarray coords, np::ndarray centroid, np::ndarray bbodx, np::ndarray &o_ptr)
Internal implementation for topology mode generation.
np::ndarray convertToNumPy(std::vector< double > &data, int rows, int nb_gauss_pts)
Convert std::vector to NumPy array for Python interface.
MoFEMErrorCode numberOfModes(int block_id, int &modes)
Return number of topology optimization modes for given material block.

◆ blockModesImpl()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::blockModesImpl ( int  block_id,
np::ndarray  coords,
np::ndarray  centroid,
np::ndarray  bbodx,
np::ndarray &  o_ptr 
)
private

Internal implementation for topology mode generation.

Calls Python function to generate spatial basis functions for topology optimization. These modes define the design space and parametrize allowable geometry modifications during optimization.

Parameters
block_idMaterial block identifier
coordsNumPy array of element coordinates
centroidNumPy array of block centroid
bbodxNumPy array of bounding box dimensions
o_ptrOutput NumPy array for mode vectors
Returns
MoFEMErrorCode Success or error code

Definition at line 1254 of file ObjectiveFunctionData.cpp.

1258 {
1260 try {
1261 if (bp::extract<bool>(mainNamespace.attr("__contains__")("block_modes"))) {
1262 o = bp::extract<np::ndarray>(
1263 mainNamespace["block_modes"](block_id, coords, centroid, bbodx));
1264 } else {
1267 "Python function block_modes(block_id,coords,centroid,bbox) is not "
1268 "defined");
1269 }
1270 } catch (bp::error_already_set const &) {
1271 // print all other errors to stderr
1272 PyErr_Print();
1274 }
1276}
bp::object mainNamespace
Main Python namespace for script execution.

◆ boundaryObjectiveFunctionImpl()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::boundaryObjectiveFunctionImpl ( np::ndarray  coords,
np::ndarray  u,
np::ndarray  t,
np::ndarray &  o 
)
private

Definition at line 1178 of file ObjectiveFunctionData.cpp.

1184 {
1186 try {
1187
1188 if (bp::extract<bool>(mainNamespace.attr("__contains__")("f_boundary"))) {
1189 o = bp::extract<np::ndarray>(mainNamespace["f_boundary"](coords, u, t));
1190 } else if (bp::extract<bool>(
1191 mainNamespace.attr("__contains__")("f_boundary_function"))) {
1192 o = bp::extract<np::ndarray>(
1193 mainNamespace["f_boundary_function"](coords, u, t));
1194 } else {
1197 "Python function f_boundary(coords,u,t) is not defined");
1198 }
1199
1200 } catch (bp::error_already_set const &) {
1201 PyErr_Print();
1203 }
1205}
constexpr double t
plate stiffness
Definition plate.cpp:58

◆ boundaryObjectiveGradientTractionImpl()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::boundaryObjectiveGradientTractionImpl ( np::ndarray  coords,
np::ndarray  u,
np::ndarray  t,
np::ndarray &  o 
)
private

Definition at line 1153 of file ObjectiveFunctionData.cpp.

1159 {
1161 try {
1162
1163 if (bp::extract<bool>(mainNamespace.attr("__contains__")("f_boundary_t"))) {
1164 o = bp::extract<np::ndarray>(mainNamespace["f_boundary_t"](coords, u, t));
1165 } else {
1168 "Python function f_boundary_t(coords,u,t) is not defined");
1169 }
1170
1171 } catch (bp::error_already_set const &) {
1172 PyErr_Print();
1174 }
1176}

◆ boundaryObjectiveGradientUImpl()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::boundaryObjectiveGradientUImpl ( np::ndarray  coords,
np::ndarray  u,
np::ndarray  t,
np::ndarray &  o 
)
private

Definition at line 1207 of file ObjectiveFunctionData.cpp.

1213 {
1215 try {
1216
1217 if (bp::extract<bool>(mainNamespace.attr("__contains__")("f_boundary_u"))) {
1218 o = bp::extract<np::ndarray>(mainNamespace["f_boundary_u"](coords, u, t));
1219 } else {
1222 "Python function f_boundary_u(coords,u,t) is not defined");
1223 }
1224
1225 } catch (bp::error_already_set const &) {
1226 PyErr_Print();
1228 }
1230}

◆ convertToNumPy() [1/2]

np::ndarray ShapeOptimization::ObjectiveFunctionDataImpl::convertToNumPy ( double *  ptr,
int  s 
)
inlineprivate

Convert raw pointer to NumPy array for Python interface.

Low-level conversion for direct memory access to create NumPy arrays. Provides zero-copy conversion when possible for performance.

Parameters
ptrRaw data pointer
sArray size
Returns
np::ndarray NumPy array for Python use

Definition at line 1307 of file ObjectiveFunctionData.cpp.

1308 {
1309 auto dtype = np::dtype::get_builtin<double>();
1310 auto size = bp::make_tuple(s);
1311 auto stride = bp::make_tuple(sizeof(double));
1312 return (np::from_data(ptr, dtype, size, stride, bp::object()));
1313}

◆ convertToNumPy() [2/2]

np::ndarray ShapeOptimization::ObjectiveFunctionDataImpl::convertToNumPy ( std::vector< double > &  data,
int  rows,
int  nb_gauss_pts 
)
inlineprivate

Convert std::vector to NumPy array for Python interface.

Converts a std::vector<double> to a NumPy ndarray.

Efficient conversion from MoFEM data structures to NumPy arrays for seamless Python function calls without data copying.

Parameters
dataSource vector data
rowsNumber of rows in resulting array
nb_gauss_ptsNumber of Gauss points (affects array structure)
Returns
np::ndarray NumPy array for Python use

This function wraps the given vector data into a NumPy array with the specified number of rows and Gauss points. The resulting ndarray shares memory with the input vector, so changes to one will affect the other.

Parameters
dataReference to the vector containing double values to be converted.
rowsNumber of rows in the resulting NumPy array.
nb_gauss_ptsNumber of Gauss points (columns) in the resulting NumPy array.
Returns
np::ndarray NumPy array view of the input data.
Note
  • size specifies the shape of the resulting ndarray as a tuple (rows, nb_gauss_pts).
  • stride specifies the step size in bytes to move to the next element in memory. Here, it is set to sizeof(double), indicating contiguous storage for each element.

Definition at line 1299 of file ObjectiveFunctionData.cpp.

1300 {
1301 auto dtype = np::dtype::get_builtin<double>();
1302 auto size = bp::make_tuple(rows, nb_gauss_pts);
1303 auto stride = bp::make_tuple(nb_gauss_pts * sizeof(double), sizeof(double));
1304 return (np::from_data(data.data(), dtype, size, stride, bp::object()));
1305}

◆ copyToFull()

MatrixDouble ShapeOptimization::ObjectiveFunctionDataImpl::copyToFull ( MatrixDouble &  s)
private

Convert symmetric tensor storage to full matrix format.

Definition at line 418 of file ObjectiveFunctionData.cpp.

418 {
419 const auto nb_gauss_pts = s.size1();
420 MatrixDouble f(nb_gauss_pts, 9);
421 f.clear();
424 auto t_f =
426 f);
427 auto t_s = getFTensor2SymmetricFromMat<SPACE_DIM>(s);
428 for (size_t ii = 0; ii != nb_gauss_pts; ++ii) {
429 t_f(i, j) = t_s(i, j);
430 ++t_f;
431 ++t_s;
432 }
433 return f;
434};
#define FTENSOR_INDEX(DIM, I)
FTensor::Index< 'i', SPACE_DIM > i
FTensor::Index< 'j', 3 > j
auto getFTensor2FromMat(M &data)
Get tensor rank 2 (matrix) form data matrix.
constexpr int SPACE_DIM
Space dimension of problem (2D or 3D), set at compile time.

◆ copyToSymmetric()

void ShapeOptimization::ObjectiveFunctionDataImpl::copyToSymmetric ( double *  ptr,
MatrixDouble &  s 
)
private

Convert full matrix to symmetric tensor storage format.

Definition at line 436 of file ObjectiveFunctionData.cpp.

436 {
437 const auto nb_gauss_pts = s.size1();
440 auto t_f =
442 ptr);
443
444 auto t_s = getFTensor2SymmetricFromMat<SPACE_DIM>(s);
445 for (size_t ii = 0; ii != nb_gauss_pts; ++ii) {
446 t_s(i, j) = (t_f(i, j) || t_f(j, i)) / 2.0;
447 ++t_f;
448 ++t_s;
449 }
450}
auto getFTensor2FromPtr(double *ptr)

◆ evalBoundaryObjectiveFunction()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::evalBoundaryObjectiveFunction ( MatrixDouble &  coords,
boost::shared_ptr< MatrixDouble >  u_ptr,
boost::shared_ptr< MatrixDouble >  t_ptr,
boost::shared_ptr< VectorDouble >  o_ptr,
bool  symmetrize = true 
)
virtual

Implements ShapeOptimization::ObjectiveFunctionData.

Definition at line 853 of file ObjectiveFunctionData.cpp.

856 {
858 try {
859 (void)symmetrize;
860
861 auto np_coords =
862 convertToNumPy(coords.data(), coords.size1(), coords.size2());
863 auto np_u = convertToNumPy(u_ptr->data(), u_ptr->size1(), u_ptr->size2());
864 auto np_t = convertToNumPy(t_ptr->data(), t_ptr->size1(), t_ptr->size2());
865
866 np::ndarray np_output = np::empty(bp::make_tuple(t_ptr->size2()),
867 np::dtype::get_builtin<double>());
868
869 CHKERR boundaryObjectiveFunctionImpl(np_coords, np_u, np_t, np_output);
870
871 // Check the shape of returned array
872 if (np_output.get_nd() != 1 || np_output.get_shape()[0] != t_ptr->size2()) {
875 "Wrong shape of Objective Function from python expected (" +
876 std::to_string(t_ptr->size2()) + "), got (" +
877 std::to_string(np_output.get_shape()[0]) + ")");
878 }
879
880 o_ptr->resize(t_ptr->size2(), false);
881 double *val_ptr = reinterpret_cast<double *>(np_output.get_data());
882 std::copy(val_ptr, val_ptr + t_ptr->size2(), o_ptr->data().begin());
883
884 } catch (bp::error_already_set const &) {
885 PyErr_Print();
887 }
889}
MoFEMErrorCode boundaryObjectiveFunctionImpl(np::ndarray coords, np::ndarray u, np::ndarray t, np::ndarray &o)

◆ evalBoundaryObjectiveGradientTraction()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::evalBoundaryObjectiveGradientTraction ( MatrixDouble &  coords,
boost::shared_ptr< MatrixDouble >  u_ptr,
boost::shared_ptr< MatrixDouble >  t_ptr,
boost::shared_ptr< MatrixDouble >  o_ptr 
)
virtual

Evaluate gradient of objective function w.r.t. traction-like vector field.

Implements ShapeOptimization::ObjectiveFunctionData.

Definition at line 811 of file ObjectiveFunctionData.cpp.

814 {
816 try {
817
818 auto np_coords =
819 convertToNumPy(coords.data(), coords.size1(), coords.size2());
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());
822
823 np::ndarray np_output =
824 np::empty(bp::make_tuple(u_ptr->size1(), u_ptr->size2()),
825 np::dtype::get_builtin<double>());
826
827 CHKERR boundaryObjectiveGradientTractionImpl(np_coords, np_u, np_t, np_output);
828
829 // Check the shape of returned array
830 if (np_output.get_shape()[0] != u_ptr->size1() ||
831 np_output.get_shape()[1] != u_ptr->size2()) {
834 "Wrong shape of Objective Gradient from python expected (" +
835 std::to_string(u_ptr->size1()) + ", " +
836 std::to_string(u_ptr->size2()) + "), got (" +
837 std::to_string(np_output.get_shape()[0]) + ", " +
838 std::to_string(np_output.get_shape()[1]) + ")");
839 }
840
841 o_ptr->resize(u_ptr->size1(), u_ptr->size2(), false);
842 double *val_ptr = reinterpret_cast<double *>(np_output.get_data());
843 std::copy(val_ptr, val_ptr + u_ptr->size1() * u_ptr->size2(),
844 o_ptr->data().begin());
845
846 } catch (bp::error_already_set const &) {
847 PyErr_Print();
849 }
851}
MoFEMErrorCode boundaryObjectiveGradientTractionImpl(np::ndarray coords, np::ndarray u, np::ndarray t, np::ndarray &o)

◆ evalBoundaryObjectiveGradientU()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::evalBoundaryObjectiveGradientU ( MatrixDouble &  coords,
boost::shared_ptr< MatrixDouble >  u_ptr,
boost::shared_ptr< MatrixDouble >  t_ptr,
boost::shared_ptr< MatrixDouble >  o_ptr 
)
virtual

Implements ShapeOptimization::ObjectiveFunctionData.

Definition at line 891 of file ObjectiveFunctionData.cpp.

894 {
896 try {
897 auto np_coords =
898 convertToNumPy(coords.data(), coords.size1(), coords.size2());
899 auto np_u = convertToNumPy(u_ptr->data(), u_ptr->size1(), u_ptr->size2());
900 auto np_t = convertToNumPy(t_ptr->data(), t_ptr->size1(), t_ptr->size2());
901
902 np::ndarray np_output =
903 np::empty(bp::make_tuple(u_ptr->size1(), u_ptr->size2()),
904 np::dtype::get_builtin<double>());
905
906 CHKERR boundaryObjectiveGradientUImpl(np_coords, np_u, np_t, np_output);
907
908 // Check the shape of returned array
909 if (np_output.get_shape()[0] != u_ptr->size1() ||
910 np_output.get_shape()[1] != u_ptr->size2()) {
913 "Wrong shape of Objective Gradient from python expected (" +
914 std::to_string(u_ptr->size1()) + ", " +
915 std::to_string(u_ptr->size2()) + "), got (" +
916 std::to_string(np_output.get_shape()[0]) + ", " +
917 std::to_string(np_output.get_shape()[1]) + ")");
918 }
919
920 o_ptr->resize(u_ptr->size1(), u_ptr->size2(), false);
921 double *val_ptr = reinterpret_cast<double *>(np_output.get_data());
922 std::copy(val_ptr, val_ptr + u_ptr->size1() * u_ptr->size2(),
923 o_ptr->data().begin());
924
925 } catch (bp::error_already_set const &) {
926 PyErr_Print();
928 }
930}
MoFEMErrorCode boundaryObjectiveGradientUImpl(np::ndarray coords, np::ndarray u, np::ndarray t, np::ndarray &o)

◆ evalInteriorObjectiveFunction()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::evalInteriorObjectiveFunction ( 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 
)
virtual

Evaluate objective function at current state.

Evaluate objective function at current finite element state.

Calls Python-defined objective function with current displacement, stress, and strain fields. Used during optimization to compute the objective value that drives the optimization process.

Parameters
coordsGauss point coordinates
u_ptrDisplacement field values
stress_ptrStress tensor values
strain_ptrStrain tensor values
o_ptrOutput objective function values
Returns
MoFEMErrorCode Success or error code

This method bridges MoFEM finite element data with Python-defined objective functions for topology optimization. It handles the complete data conversion workflow from MoFEM matrices to NumPy arrays, calls the Python objective function, and converts results back to MoFEM format.

Process:

  1. Convert coordinate matrix to NumPy format for Python access
  2. Convert displacement field data to NumPy arrays
  3. Convert symmetric stress/strain tensors to full 3x3 matrix format
  4. Call Python objective function: f(coords, u, stress, strain)
  5. Extract results and copy back to MoFEM vector format

The objective function typically computes scalar quantities like:

  • Compliance: ∫ u^T * f dΩ (minimize structural deformation)
  • Stress constraints: ∫ ||σ - σ_target||² dΩ (control stress distribution)
  • Volume constraints: ∫ ρ dΩ (material usage limitations)
Parameters
coordsGauss point coordinates for current element
u_ptrDisplacement field values at Gauss points
stress_ptrCauchy stress tensor values (symmetric storage)
strain_ptrStrain tensor values (symmetric storage)
o_ptrOutput objective function values at each Gauss point
Returns
MoFEMErrorCode Success or error code

Implements ShapeOptimization::ObjectiveFunctionData.

Definition at line 479 of file ObjectiveFunctionData.cpp.

483 {
485 try {
486
487 // Convert coordinates to NumPy array for Python function
488 auto np_coords =
489 convertToNumPy(coords.data(), coords.size1(), coords.size2());
490 // Convert displacement field to NumPy array
491 auto np_u = convertToNumPy(u_ptr->data(), u_ptr->size1(), u_ptr->size2());
492
493 // Convert symmetric tensor storage to full matrix format for Python
494 // MoFEM stores symmetric tensors in like Voigt notation, Python expects full 3x3 matrices
495 auto full_stress = symmetrize ? copyToFull(*(stress_ptr)) : *(stress_ptr);
496 auto full_strain = symmetrize ? copyToFull(*(strain_ptr)) : *(strain_ptr);
497
498 // Create NumPy arrays for stress and strain tensors
499 auto np_stress = convertToNumPy(full_stress.data(), full_stress.size1(),
500 full_stress.size2());
501 auto np_strain = convertToNumPy(full_strain.data(), full_strain.size1(),
502 full_strain.size2());
503
504 // Prepare output array for objective function values
505 const auto nb_gauss_pts = full_strain.size1();
506 np::ndarray np_output =
507 np::empty(bp::make_tuple(nb_gauss_pts), np::dtype::get_builtin<double>());
508
509 // Call Python objective function implementation
510 CHKERR interiorObjectiveFunctionImpl(np_coords, np_u, np_stress, np_strain,
511 np_output);
512
513 //Check the shape of returned array
514 if (np_output.get_nd() != 1 || np_output.get_shape()[0] != nb_gauss_pts) {
517 "Wrong shape of Objective Function from python expected (" +
518 std::to_string(nb_gauss_pts) + "), got (" +
519 std::to_string(np_output.get_shape()[0]) + ")");
520 }
521
522 // Copy Python results back to a 1 x n matrix, matching common-data storage.
523 o_ptr->resize(1, nb_gauss_pts, false);
524 double *val_ptr = reinterpret_cast<double *>(np_output.get_data());
525 std::copy(val_ptr, val_ptr + nb_gauss_pts, o_ptr->data().begin());
526
527 } catch (bp::error_already_set const &) {
528 // Handle Python errors with detailed error reporting
529 PyErr_Print();
531 }
533}
MoFEMErrorCode interiorObjectiveFunctionImpl(np::ndarray coords, np::ndarray u, np::ndarray stress, np::ndarray strain, np::ndarray &o)
Internal implementation for objective function evaluation.
MatrixDouble copyToFull(MatrixDouble &s)
Convert symmetric tensor storage to full matrix format.

◆ evalInteriorObjectiveGradientStrain()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::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 
)
virtual

Compute gradient of objective function with respect to strain.

Compute gradient of objective function with respect to strain tensor.

Evaluates ∂f/∂ε where f is objective function and ε is strain tensor. Used when objective function depends directly on strain measures, complementing stress-based gradients in adjoint sensitivity analysis.

Parameters
coordsGauss point coordinates
u_ptrDisplacement field values
stress_ptrStress tensor values
strain_ptrStrain tensor values
o_ptrOutput gradient values
Returns
MoFEMErrorCode Success or error code

This method evaluates ∂f/∂ε, the partial derivative of the objective function with respect to the strain tensor. While many structural objectives depend primarily on stress, strain-based gradients are important for certain optimization formulations and provide additional sensitivity information.

Mathematical context: For strain energy-based objectives: f = ½ε:C:ε The gradient is: ∂f/∂ε = C:ε = σ (stress tensor)

For strain-based constraints or objectives like strain concentration: ∂f/∂ε = ∂/∂ε[∫(ε_vm - ε_target)² dΩ] = 2(ε_vm - ε_target) * ∂ε_vm/∂ε

Process:

  1. Convert field data to NumPy format for Python compatibility
  2. Call Python function f_strain(coords, u, stress, strain)
  3. Python returns gradient matrices ∂f/∂ε for each Gauss point
  4. Convert from full 3x3 format back to symmetric storage
  5. Results used in adjoint sensitivity analysis

This gradient complements stress-based gradients in comprehensive sensitivity analysis for topology optimization problems.

Parameters
coordsGauss point coordinates
u_ptrDisplacement field values
stress_ptrCurrent stress tensor values (symmetric storage)
strain_ptrCurrent strain tensor values (symmetric storage)
o_ptrOutput strain gradients ∂f/∂ε (symmetric storage)
Returns
MoFEMErrorCode Success or error code

Implements ShapeOptimization::ObjectiveFunctionData.

Definition at line 659 of file ObjectiveFunctionData.cpp.

663 {
665 try {
666
667 // Convert coordinates and displacement data to NumPy format
668 auto np_coords =
669 convertToNumPy(coords.data(), coords.size1(), coords.size2());
670 auto np_u = convertToNumPy(u_ptr->data(), u_ptr->size1(), u_ptr->size2());
671
672 // Convert symmetric tensor data to full 3x3 matrices for Python
673 auto full_stress = symmetrize ? copyToFull(*(stress_ptr)) : *(stress_ptr);
674 auto full_strain = symmetrize ? copyToFull(*(strain_ptr)) : *(strain_ptr);
675
676 auto np_stress = convertToNumPy(full_stress.data(), full_stress.size1(),
677 full_stress.size2());
678 auto np_strain = convertToNumPy(full_strain.data(), full_strain.size1(),
679 full_strain.size2());
680
681 // Prepare output array for strain gradients
682 np::ndarray np_output =
683 np::empty(bp::make_tuple(full_strain.size1(), full_strain.size2()),
684 np::dtype::get_builtin<double>());
685
686 // Call Python implementation for strain gradient computation
687 CHKERR interiorObjectiveGradientStrainImpl(np_coords, np_u, np_stress, np_strain,
688 np_output);
689
690 // Check the shape of returned array
691 if (np_output.get_shape()[0] != full_strain.size1() ||
692 np_output.get_shape()[1] != full_strain.size2()) {
695 "Wrong shape of Objective Gradient from python expected (" +
696 std::to_string(full_strain.size1()) + ", " +
697 std::to_string(full_strain.size2()) + "), got (" +
698 std::to_string(np_output.get_shape()[0]) + ", " +
699 std::to_string(np_output.get_shape()[1]) + ")");
700 }
701
702 o_ptr->resize(strain_ptr->size1(), strain_ptr->size2(), false);
703 if (symmetrize) {
704 double *val_ptr = reinterpret_cast<double *>(np_output.get_data());
705 copyToSymmetric(val_ptr, *(o_ptr));
706 } else {
707 double *val_ptr = reinterpret_cast<double *>(np_output.get_data());
708 std::copy(val_ptr, val_ptr + strain_ptr->size1() * strain_ptr->size2(),
709 o_ptr->data().begin());
710 }
711
712 } catch (bp::error_already_set const &) {
713 PyErr_Print();
715 }
717}
MoFEMErrorCode interiorObjectiveGradientStrainImpl(np::ndarray coords, np::ndarray u, np::ndarray stress, np::ndarray strain, np::ndarray &o)
Internal implementation for strain gradient computation.
void copyToSymmetric(double *ptr, MatrixDouble &s)
Convert full matrix to symmetric tensor storage format.

◆ evalInteriorObjectiveGradientStress()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::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 
)
virtual

Compute gradient of objective function with respect to stress.

Compute gradient of objective function with respect to stress tensor.

Evaluates ∂f/∂σ where f is objective function and σ is stress tensor. This gradient is used in the adjoint method to compute sensitivities efficiently. Essential for gradient-based topology optimization.

Parameters
coordsGauss point coordinates
u_ptrDisplacement field values
stress_ptrStress tensor values
strain_ptrStrain tensor values
o_ptrOutput gradient values
Returns
MoFEMErrorCode Success or error code

This method evaluates ∂f/∂σ, the partial derivative of the objective function with respect to the Cauchy stress tensor. This gradient is fundamental to the adjoint method for topology optimization, as it provides the driving force for the adjoint equation solution.

Mathematical context: The adjoint method requires ∂f/∂σ to compute sensitivities efficiently. For stress-based objectives like von Mises stress constraints: ∂f/∂σ = ∂/∂σ[∫(σ_vm - σ_target)² dΩ] = 2(σ_vm - σ_target) * ∂σ_vm/∂σ

Process:

  1. Convert all field data to NumPy format for Python processing
  2. Call Python function f_stress(coords, u, stress, strain)
  3. Python returns full 3x3 gradient matrices for each Gauss point
  4. Convert back to symmetric tensor storage used by MoFEM
  5. Store results for use in adjoint equation assembly

The resulting gradients drive the adjoint solution that enables efficient computation of design sensitivities independent of design variable count.

Parameters
coordsGauss point coordinates
u_ptrDisplacement field values
stress_ptrCurrent stress tensor values (symmetric storage)
strain_ptrCurrent strain tensor values (symmetric storage)
o_ptrOutput stress gradients ∂f/∂σ (symmetric storage)
Returns
MoFEMErrorCode Success or error code

Implements ShapeOptimization::ObjectiveFunctionData.

Definition at line 565 of file ObjectiveFunctionData.cpp.

569 {
571 try {
572
573 // Convert coordinates and displacement field to NumPy format
574 auto np_coords =
575 convertToNumPy(coords.data(), coords.size1(), coords.size2());
576 auto np_u = convertToNumPy(u_ptr->data(), u_ptr->size1(), u_ptr->size2());
577
578 // Convert symmetric tensors to full 3x3 format for Python processing
579 auto full_stress = symmetrize ? copyToFull(*(stress_ptr)) : *(stress_ptr);
580 auto full_strain = symmetrize ? copyToFull(*(strain_ptr)) : *(strain_ptr);
581
582 // Create NumPy arrays for stress and strain tensors
583 auto np_stress = convertToNumPy(full_stress.data(), full_stress.size1(),
584 full_stress.size2());
585 auto np_strain = convertToNumPy(full_strain.data(), full_strain.size1(),
586 full_strain.size2());
587 // Prepare output array for stress gradients (full matrix format)
588 np::ndarray np_output =
589 np::empty(bp::make_tuple(full_strain.size1(), full_strain.size2()),
590 np::dtype::get_builtin<double>());
591
592 // Call Python implementation for stress gradient computation
593 CHKERR interiorObjectiveGradientStressImpl(np_coords, np_u, np_stress, np_strain,
594 np_output);
595
596 // Check the shape of returned array
597 if (np_output.get_shape()[0] != full_strain.size1() ||
598 np_output.get_shape()[1] != full_strain.size2()) {
601 "Wrong shape of Objective Gradient from python expected (" +
602 std::to_string(full_strain.size1()) + ", " +
603 std::to_string(full_strain.size2()) + "), got (" +
604 std::to_string(np_output.get_shape()[0]) + ", " +
605 std::to_string(np_output.get_shape()[1]) + ")");
606 }
607
608 // Prepare output matrix in the requested tensor storage format
609 o_ptr->resize(stress_ptr->size1(), stress_ptr->size2(), false);
610 if (symmetrize) {
611 double *val_ptr = reinterpret_cast<double *>(np_output.get_data());
612 // Convert full matrix results back to symmetric tensor storage
613 copyToSymmetric(val_ptr, *(o_ptr));
614 } else {
615 double *val_ptr = reinterpret_cast<double *>(np_output.get_data());
616 std::copy(val_ptr, val_ptr + stress_ptr->size1() * stress_ptr->size2(),
617 o_ptr->data().begin());
618 }
619
620 } catch (bp::error_already_set const &) {
621 PyErr_Print();
623 }
625}
MoFEMErrorCode interiorObjectiveGradientStressImpl(np::ndarray coords, np::ndarray u, np::ndarray stress, np::ndarray strain, np::ndarray &o)
Internal implementation for stress gradient computation.

◆ evalInteriorObjectiveGradientU()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::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 
)
virtual

Compute gradient of objective function with respect to displacement.

Compute gradient of objective function with respect to displacement field.

Evaluates ∂f/∂u where f is objective function and u is displacement field. This provides direct sensitivity of objective to displacement changes, used as right-hand side in adjoint equation K^T * λ = ∂f/∂u.

Parameters
coordsGauss point coordinates
u_ptrDisplacement field values
stress_ptrStress tensor values
strain_ptrStrain tensor values
o_ptrOutput gradient values
Returns
MoFEMErrorCode Success or error code

This method evaluates ∂f/∂u, the partial derivative of the objective function
with respect to the displacement field. This gradient is crucial for the adjoint method as it forms the right-hand side of the adjoint equation: K^T * λ = ∂f/∂u

Mathematical context: The adjoint method solves: K^T * λ = ∂f/∂u where λ are the adjoint variables (Lagrange multipliers)

For compliance minimization: f = ½u^T * K * u The gradient is: ∂f/∂u = K * u (applied forces)

For displacement-based constraints: f = ||u - u_target||² The gradient is: ∂f/∂u = 2(u - u_target)

Process:

  1. Convert all field data to NumPy format for Python processing
  2. Call Python function f_u(coords, u, stress, strain)
  3. Python returns displacement gradients for each component
  4. Copy results directly (no tensor conversion needed for vectors)
  5. Results drive adjoint equation solution for sensitivity analysis

This gradient is fundamental to adjoint-based topology optimization, enabling efficient sensitivity computation for any number of design variables.

Parameters
coordsGauss point coordinates
u_ptrDisplacement field values
stress_ptrCurrent stress tensor values
strain_ptrCurrent strain tensor values
o_ptrOutput displacement gradients ∂f/∂u
Returns
MoFEMErrorCode Success or error code

Implements ShapeOptimization::ObjectiveFunctionData.

Definition at line 753 of file ObjectiveFunctionData.cpp.

757 {
759 try {
760
761 // Convert coordinates and displacement field to NumPy format
762 auto np_coords =
763 convertToNumPy(coords.data(), coords.size1(), coords.size2());
764 auto np_u = convertToNumPy(u_ptr->data(), u_ptr->size1(), u_ptr->size2());
765
766 // Convert stress and strain tensors to full matrix format
767 auto full_stress = symmetrize ? copyToFull(*(stress_ptr)) : *(stress_ptr);
768 auto full_strain = symmetrize ? copyToFull(*(strain_ptr)) : *(strain_ptr);
769
770 auto np_stress = convertToNumPy(full_stress.data(), full_stress.size1(),
771 full_stress.size2());
772 auto np_strain = convertToNumPy(full_strain.data(), full_strain.size1(),
773 full_strain.size2());
774
775 // Prepare output array for displacement gradients (same size as displacement field)
776 np::ndarray np_output =
777 np::empty(bp::make_tuple(u_ptr->size1(), u_ptr->size2()),
778 np::dtype::get_builtin<double>());
779
780 // Call Python implementation for displacement gradient computation
781 // Note: This should call interiorObjectiveGradientUImpl, not interiorObjectiveGradientStrainImpl
782 CHKERR interiorObjectiveGradientUImpl(np_coords, np_u, np_stress, np_strain,
783 np_output);
784
785 // Check the shape of returned array
786 if (np_output.get_shape()[0] != u_ptr->size1() ||
787 np_output.get_shape()[1] != u_ptr->size2()) {
790 "Wrong shape of Objective Gradient from python expected (" +
791 std::to_string(u_ptr->size1()) + ", " +
792 std::to_string(u_ptr->size2()) + "), got (" +
793 std::to_string(np_output.get_shape()[0]) + ", " +
794 std::to_string(np_output.get_shape()[1]) + ")");
795 }
796
797 // Copy results directly to output matrix (no tensor conversion needed for vectors)
798 o_ptr->resize(u_ptr->size1(), u_ptr->size2(), false);
799 double *val_ptr = reinterpret_cast<double *>(np_output.get_data());
800 std::copy(val_ptr, val_ptr + u_ptr->size1() * u_ptr->size2(),
801 o_ptr->data().begin());
802
803 } catch (bp::error_already_set const &) {
804 // Handle Python errors with detailed reporting
805 PyErr_Print();
807 }
809}
MoFEMErrorCode interiorObjectiveGradientUImpl(np::ndarray coords, np::ndarray u, np::ndarray stress, np::ndarray strain, np::ndarray &o)
Internal implementation for displacement gradient computation.

◆ initPython()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::initPython ( const std::string  py_file)

Initialize Python interpreter and load objective function script.

This method sets up the Python environment for objective function evaluation by loading a Python script that defines the required optimization functions. It establishes the bridge between MoFEM's C++ finite element computations and user-defined Python objective functions.

The Python script must define the following functions:

  • f(coords, u, stress, strain): Main objective function
  • f_stress(coords, u, stress, strain): Gradient w.r.t. stress ∂f/∂σ
  • f_strain(coords, u, stress, strain): Gradient w.r.t. strain ∂f/∂ε
  • f_u(coords, u, stress, strain): Gradient w.r.t. displacement ∂f/∂u
  • number_of_modes(block_id): Return number of topology modes
  • block_modes(block_id, coords, centroid, bbox): Define topology modes

All functions receive NumPy arrays and must return NumPy arrays of appropriate dimensions for the finite element computation.

Parameters
py_filePath to Python script containing objective function definitions
Returns
MoFEMErrorCode Success or error code
Exceptions
MOFEM_OPERATION_UNSUCCESSFULif Python script has errors

Definition at line 397 of file ObjectiveFunctionData.cpp.

397 {
399 try {
400
401 // Create main Python module and namespace for script execution
402 auto main_module = bp::import("__main__");
403 mainNamespace = main_module.attr("__dict__");
404
405 // Execute the Python script in the main namespace
406 bp::exec_file(py_file.c_str(), mainNamespace, mainNamespace);
407
408 // Python callbacks are resolved lazily with explicit existence checks
409
410 } catch (bp::error_already_set const &) {
411 // Handle Python errors by printing to stderr and throwing MoFEM exception
412 PyErr_Print();
414 }
416}

◆ interiorObjectiveFunctionImpl()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::interiorObjectiveFunctionImpl ( np::ndarray  coords,
np::ndarray  u,
np::ndarray  stress,
np::ndarray  strain,
np::ndarray &  o 
)
private

Internal implementation for objective function evaluation.

Handles low-level Python function call with NumPy array conversion. Converts MoFEM matrices to NumPy arrays, calls Python function, and handles return value conversion.

Parameters
coordsNumPy array of coordinates
uNumPy array of displacements
stressNumPy array of stress tensors
strainNumPy array of strain tensors
oOutput NumPy array for objective values
Returns
MoFEMErrorCode Success or error code

Definition at line 1025 of file ObjectiveFunctionData.cpp.

1031 {
1033 try {
1034
1035 if (bp::extract<bool>(mainNamespace.attr("__contains__")("f"))) {
1036 // Deprecated: Check for main objective function 'f' first for backward compatibility
1037 o = bp::extract<np::ndarray>(
1038 mainNamespace["f"](coords, u, stress, strain));
1039 } else if (bp::extract<bool>(
1040 mainNamespace.attr("__contains__")("f_interior"))) {
1041 o = bp::extract<np::ndarray>(
1042 mainNamespace["f_interior"](coords, u, stress, strain));
1043 } else {
1046 "Python function f_interior(coords,u,stress,strain) is not defined");
1047 }
1048
1049 } catch (bp::error_already_set const &) {
1050 // print all other errors to stderr
1051 PyErr_Print();
1053 }
1055}

◆ interiorObjectiveGradientStrainImpl()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::interiorObjectiveGradientStrainImpl ( np::ndarray  coords,
np::ndarray  u,
np::ndarray  stress,
np::ndarray  strain,
np::ndarray &  o 
)
private

Internal implementation for strain gradient computation.

Evaluates ∂f/∂ε through Python interface with NumPy array handling. Provides strain-based sensitivities for comprehensive gradient computation.

Parameters
coordsNumPy array of coordinates
uNumPy array of displacements
stressNumPy array of stress tensors
strainNumPy array of strain tensors
oOutput NumPy array for gradient values
Returns
MoFEMErrorCode Success or error code

Definition at line 1089 of file ObjectiveFunctionData.cpp.

1095 {
1097 try {
1098
1099 if (bp::extract<bool>(mainNamespace.attr("__contains__")("f_strain"))) {
1100 // Deprecated: keep legacy name first for backward compatibility
1101 o = bp::extract<np::ndarray>(
1102 mainNamespace["f_strain"](coords, u, stress, strain));
1103 } else if (bp::extract<bool>(
1104 mainNamespace.attr("__contains__")("f_interior_strain"))) {
1105 o = bp::extract<np::ndarray>(
1106 mainNamespace["f_interior_strain"](coords, u, stress, strain));
1107 } else {
1110 "Python function f_interior_strain(coords,u,stress,strain) is not defined");
1111 }
1112
1113 } catch (bp::error_already_set const &) {
1114 // print all other errors to stderr
1115 PyErr_Print();
1117 }
1119}

◆ interiorObjectiveGradientStressImpl()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::interiorObjectiveGradientStressImpl ( np::ndarray  coords,
np::ndarray  u,
np::ndarray  stress,
np::ndarray  strain,
np::ndarray &  o 
)
private

Internal implementation for stress gradient computation.

Calls Python function to compute ∂f/∂σ with automatic array conversion. Essential for adjoint-based sensitivity analysis in topology optimization.

Parameters
coordsNumPy array of coordinates
uNumPy array of displacements
stressNumPy array of stress tensors
strainNumPy array of strain tensors
oOutput NumPy array for gradient values
Returns
MoFEMErrorCode Success or error code

Definition at line 1057 of file ObjectiveFunctionData.cpp.

1063 {
1065 try {
1066
1067 if (bp::extract<bool>(mainNamespace.attr("__contains__")("f_stress"))) {
1068 // Deprecated: keep legacy name first for backward compatibility
1069 o = bp::extract<np::ndarray>(
1070 mainNamespace["f_stress"](coords, u, stress, strain));
1071 } else if (bp::extract<bool>(
1072 mainNamespace.attr("__contains__")("f_interior_stress"))) {
1073 o = bp::extract<np::ndarray>(
1074 mainNamespace["f_interior_stress"](coords, u, stress, strain));
1075 } else {
1078 "Python function f_interior_stress(coords,u,stress,strain) is not defined");
1079 }
1080
1081 } catch (bp::error_already_set const &) {
1082 // print all other errors to stderr
1083 PyErr_Print();
1085 }
1087}

◆ interiorObjectiveGradientUImpl()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::interiorObjectiveGradientUImpl ( np::ndarray  coords,
np::ndarray  u,
np::ndarray  stress,
np::ndarray  strain,
np::ndarray &  o 
)
private

Internal implementation for displacement gradient computation.

Computes ∂f/∂u through Python interface for adjoint equation right-hand side. This gradient drives the adjoint solution that enables efficient sensitivity computation independent of design variable count.

Parameters
coordsNumPy array of coordinates
uNumPy array of displacements
stressNumPy array of stress tensors
strainNumPy array of strain tensors
oOutput NumPy array for gradient values
Returns
MoFEMErrorCode Success or error code

Definition at line 1121 of file ObjectiveFunctionData.cpp.

1127 {
1129 try {
1130
1131 if (bp::extract<bool>(mainNamespace.attr("__contains__")("f_u"))) {
1132 // Deprecated: keep legacy name first for backward compatibility
1133 o = bp::extract<np::ndarray>(
1134 mainNamespace["f_u"](coords, u, stress, strain));
1135 } else if (bp::extract<bool>(
1136 mainNamespace.attr("__contains__")("f_interior_u"))) {
1137 o = bp::extract<np::ndarray>(
1138 mainNamespace["f_interior_u"](coords, u, stress, strain));
1139 } else {
1142 "Python function f_interior_u(coords,u,stress,strain) is not defined");
1143 }
1144
1145 } catch (bp::error_already_set const &) {
1146 // print all other errors to stderr
1147 PyErr_Print();
1149 }
1151}

◆ numberOfModes()

MoFEMErrorCode ShapeOptimization::ObjectiveFunctionDataImpl::numberOfModes ( int  block_id,
int &  modes 
)
virtual

Return number of topology optimization modes for given material block.

Implements ShapeOptimization::ObjectiveFunctionData.

Definition at line 1232 of file ObjectiveFunctionData.cpp.

1233 {
1235 try {
1236
1237 if (bp::extract<bool>(
1238 mainNamespace.attr("__contains__")("number_of_modes"))) {
1239 modes = bp::extract<int>(mainNamespace["number_of_modes"](block_id));
1240 } else {
1243 "Python function number_of_modes(block_id) is not defined");
1244 }
1245
1246 } catch (bp::error_already_set const &) {
1247 // print all other errors to stderr
1248 PyErr_Print();
1250 }
1252}

Member Data Documentation

◆ mainNamespace

bp::object ShapeOptimization::ObjectiveFunctionDataImpl::mainNamespace
private

Main Python namespace for script execution.

Definition at line 180 of file ObjectiveFunctionData.cpp.


The documentation for this struct was generated from the following file: