-
Notifications
You must be signed in to change notification settings - Fork 248
Porting to PyBind11 common steps
Pybind11 comes with a module to help compilation. Such module should be included at the beginning of the CMakeLists.txt by adding:
include(pybind11Tools)
other than that one needs to change
add_library(KratosFluidDynamicsApplication SHARED ......)
to
pybind11_add_module(KratosFluidDynamicsApplication MODULE ............. )
The definition of new python modules is slightly different in Pybind than in Boost. Python the first change is that the python interfaces should be modified as in
and
The changes include:
- Removing includes of Boost python
-
using namespace boost::python
---->namespace py = pybind11;
- Adding the argument
pybind11::module& m
Aside of this the class interface is slightly changed:
- A new argument
m
(the module) has to be passed as first argument. -
bases
is not any longer required. Only its template argument must remain, in the same position of what was there before. - The
noncopyable
template argument should not be provided (everything isnoncopyable
unless specified) - if something is to me made copyable, a copy constructor should be provided to python -
init
has to be made as a .def (even thefirst
one) - a Pointer definition should be explicitly provided if the base class provides it
for example:
class_< Euler2DLaw, bases< ConstitutiveLaw >, boost::noncopyable >( "Euler2DLaw", init<>() );
becomes
py::class_< Euler2DLaw, Euler2DLaw::Pointer, ConstitutiveLaw >(m,"Euler2DLaw")
.def( py::init<>() );
One last important remark is to update the CMakeLists.txt
When references are to be used
return_internal_reference<>() ---> py::return_value_policy::reference_internal
Pybind list interface is similar to the one of boost::python
, however the extraction of data from a list is slightly different
For example:
boost::python::extract<ShellCrossSection::Pointer>(seclist[i])
Becomes:
pybind11::cast<ShellCrossSection::Pointer >( seclist[i] );
Definition of static methods is changed
.def("AddToProperties", &TClassName::AddToProperties< Variable< TClassName >>).staticmethod("AddToProperties")
Becomes
.def_static("AddToProperties", &TClassName::AddToProperties< Variable< TClassName > >)
This construct no longer exists in pybind11. Its previous use was to print a stringified version of your class. In pybind you must provide it yourself by defining the str function
.def(self_ns::str(self))
becomes
.def("__str__", &Class::ToStrFunction)
Note that a default implementation of a __str__
called PrintObject
, which should be useful for most Kratos classes, is provided in define_python.h
. It can be used as:
py::class_< SomeClass, SomeClass::Pointer, SomeBaseClass>
// other methods
.def("__str__", PrintObject<SomeClass>)
modify the following line of the file:
-DPYTHON_LIBRARY="C:\Python34\libs\python34.lib"
with
-DPYTHON_EXECUTABLE="c:/python/python34.exe"
Originally posted in this PR.
The problem
The problem appears on Windows when someone tries to link against an application. With boost, both the application code and application interface where compiled inside the same object, and their symbols exported when needed using the KRATOS_API
macro. This ended up generating a dynamic object that was the python module and contained the application itself, altogether in the same package.
Pybind changed how things work a bit while creating modules, and one of the changes made impossible to to have a python module as a dependency of one application, drawing derived apps impossible to compile with the old system (as the symbols were inside the module).
In order to solve this, we agreed to divide the applications that are dependencies into FooCore
and FooApplication
objects, much as the KratosCore
& Kratos
objects work.
This has increased the number of symbols that need to be visible from the "interface", all files that with add_xxxxx_to_python
, as they are no longer in the same place, and this is what is causing the linker errors.
Solution Just compile your application on Windows and see if there are linking errors. I identified myself the errors under 4 categories:
Missing exported classes:
class foo {}
to
class KRATOS_API(APPLICATION) foo {}
Variables:
KRATOS_DEFINE_VARIABLE(type, FOO)
to
KRATOS_DEFINE_APPLICATION_VARIABLE(APPLICATION, type, FOO)
Local Flags:
KRATOS_DEFINE_LOCAL_FLAG(FOO)
to
KRATOS_DEFINE_LOCAL_APPLICATION_FLAG(APPLICATION, FOO)
Template instantiation in the interface of non header classes
This is more tricky. If you happen to expose a templated class and such class in non header-only, you must explicitly instantiate that in your "core" application, for example in the foo_application.cpp file.
#foo.h
template<typename Ta, typename Tb> class KRATOS_API(FOO_APPLICATION) MyTemplateClass{
}
#foo.cpp
MyTemplateClass::MyTemplateClass() {
std::cout << "I am implemented in a cpp file" << std::endl;
}
and
# add_utilities_to_python.cpp
class_<MyTemplateClass<int, int>>(m, "MyTemplateClassInts").def(init<>);
class_<MyTemplateClass<double, double>>(m, "MyTemplateClassDoubles").def(init<>);
This will crash, and you need to add:
# foo_application.cpp
template class MyTemplateClass<int, int>;
template class MyTemplateClass<double, double>;
- Getting Kratos (Last compiled Release)
- Compiling Kratos
- Running an example from GiD
- Kratos input files and I/O
- Data management
- Solving strategies
- Manipulating solution values
- Multiphysics
- Video tutorials
- Style Guide
- Authorship of Kratos files
- Configure .gitignore
- How to configure clang-format
- How to use smart pointer in Kratos
- How to define adjoint elements and response functions
- Visibility and Exposure
- Namespaces and Static Classes
Kratos structure
Conventions
Solvers
Debugging, profiling and testing
- Compiling Kratos in debug mode
- Debugging Kratos using GDB
- Cross-debugging Kratos under Windows
- Debugging Kratos C++ under Windows
- Checking memory usage with Valgind
- Profiling Kratos with MAQAO
- Creating unitary tests
- Using ThreadSanitizer to detect OMP data race bugs
- Debugging Memory with ASAN
HOW TOs
- How to create applications
- Python Tutorials
- Kratos For Dummies (I)
- List of classes and variables accessible via python
- How to use Logger
- How to Create a New Application using cmake
- How to write a JSON configuration file
- How to Access DataBase
- How to use quaternions in Kratos
- How to do Mapping between nonmatching meshes
- How to use Clang-Tidy to automatically correct code
- How to use the Constitutive Law class
- How to use Serialization
- How to use GlobalPointerCommunicator
- How to use PointerMapCommunicator
- How to use the Geometry
- How to use processes for BCs
- How to use Parallel Utilities in futureproofing the code
- Porting to Pybind11 (LEGACY CODE)
- Porting to AMatrix
- How to use Cotire
- Applications: Python-modules
- How to run multiple cases using PyCOMPSs
- How to apply a function to a list of variables
- How to use Kratos Native sparse linear algebra
Utilities
Kratos API
Kratos Structural Mechanics API