Rat bindings¶
Rat is split into a suite of interdependent C++ libraries which define many classes and items to be used in together to model magnets and compute 3D magnetic simulations.
Rat classes¶
Each Rat class is usually defined in their own translation units
in each repository, for instance rat-common/include/log.hh
defines the interface for the rat::cmn::Log class which
is a utility to log information to console during calculations.
Its implementation is done in rat-common/src/log.cpp.
Most Rat classes use type definitions to implement a factory pattern that returns a shared pointer to the underlying instance of class. This eases memory management for most users by avoiding to manually free memory afterwards.
log.hh example¶namespace rat{namespace cmn{
// shared pointer definition for log
typedef std::shared_ptr<class Log> ShLogPr;
// shared pointer definition for no-output log
typedef std::shared_ptr<class NullLog> ShNullLogPr;
// logging to the terminal
class Log{
// properties
protected:
...
// methods
public:
// logo options
enum LogoType{RAT,NONE};
// constructor
explicit Log(
LogoType logo = NONE,
const std::shared_ptr<std::atomic_bool>& cancel_flag = nullptr);
// factory
static ShLogPr create(LogoType logo = NONE);
...
This factory pattern utilizes the create method to
return the corresponding shared pointer to a Log instance.
pyRat takes advantage of this workflow by using the shared pointer
as the container type for pybind11. That way Python users can
interact with Rat C++ libraries through the shared pointer.
Binding Rat classes¶
pyRat follows the Project-Rat structures by defining translation units for all classes to bind within each separated submodules: common, distmesh, etc…
pyRat also splits:
pyrat/include for bindings documentations and docstrings,
pyrat/src for bindings implementations and modules.
Header files in pyrat/include are also used for linking implementations when building pyRat.
For instance the pyrat/src/common submodule for binding Rat-Common items has the following structure:
pyrat/src/common
├── common.cpp ← Submodule binding
├── elements.cpp ← Elements namespace bindings
├── extra.cpp ← Extra namespace bindings
├── freecad.cpp ← FreeCAD class bindings
├── gauss.cpp ← Gauss class bindings
├── gmshfile.cpp ← GmshFile class bindings
├── log.cpp ← Log class bindings
├── ...
Binding a class then looks something like this to begin with:
log.cpp binding example¶// Bind
void bind(py::module_ &m) {
// Rat shorthands
using rat::cmn::Log;
using rat::cmn::ShLogPr;
// Class wrapper for Log
auto Log_cls = py::class_<Log, ShLogPr>(m, "Log", doc::Log);
// Constructors for Log
utils::add_constructors(
Log_cls, // class wrapper defined above
&Log::create, // rat::mdl::Log original constructor method
doc::Log_create, // documentation from pyrat/src/common/log.hh
py::arg("logo") = rat::cmn::Log::LogoType::NONE) // default agument;
The utils::add_constructors function is a pyRat utility to
bind the Log::create constructor method in Python in two ways:
using the
Log.create()static methodusing the
Log()constructor syntax.
Both ways are identical but the latter enables a more pythonic way of instantiating classes.
The Log class can then be added to
the common submodule among other classes:
common.cpp example¶// Init
void init(py::module_ &m) {
// Common module doc
m.doc() = doc::module_doc;
// Bind Typecast test class
Typecast::bind(m);
// Bind Common module items
Quadrilateral::bind(m); // Elements
Node::bind(m);
Log::bind(m);
Gauss::bind(m);
Serializer::bind(m);
FreeCAD::bind(m);
Opera::bind(m);
GmshFile::bind(m);
Extra::bind(m); // Standalone, might use other items as types
}}}
which can itself be added to the rat core module:
rat.cpp example¶// Python core module
PYBIND11_MODULE(rat, m) {
// Module documentation
m.doc() = pyrat::doc::module_doc;
// Module metadata
...
// Common submodule
#ifdef ENABLE_COMMON
auto common = m.def_submodule(pyrat::cmn::doc::module_name);
pyrat::cmn::init(common);
#endif // ENABLE_COMMON
...
Each Rat submodule has its own binding of the same name,
here common.cpp, which aggregates all bindings defined
in other source files, exposing a common submodule which
will is later added to the top pyrat.rat submodule in the
main pyrat/src/rat.cpp source file.
For instance the Log class should be accessed in Python
with the pyrat.rat.cmn.Log dot syntax for members.
Namespaces¶
pyRat makes use a C++ namespaces to have clean scopes.
The general structure is as follow:
pyrat::<module>::<item>::bindfor the main bind function,pyrat::<module>::<item>::doc::<name>for the docstring.
For instance:
pyrat::cmn::Log::bindfor the main bind function,pyrat::cmn::Log::doc::createfor the constructors documentation docstring,pyrat::cmn::Log::doc::msgfor themsgmethod documentation docstring,
and many others.
This clarifies where items come from and generalizes imports and usages.