Binding C++ classes to Lua
The OpenSn package provides a set of Lua bindings for the C++ classes. The bindings are generated using the LuaBridge3 library which is embedded in the OpenSn repository.
This guide explains how to bind C++ classes into Lua.
All binding code is located in lua/lib/opensn.cc
inside opensnlua::Console::Bind
.
Namespaces
Outside of the global namespace we have several of our own that group together the code functionality:
log
for logging events,aquad
for angular quadrature,logvol
for logical volumes,mesh
for mesh-related functionality,fieldfunc
for field functions,xs
for cross sections,post
for post-processing,solver
for solvers,lbs
for linear Boltzmann solvers.
The namespaces should not be changed unless directed by developers. All new bindings will be created inside the existing namespaces.
Example code for a aquad
namespace binding:
luabridge::getGlobalNamespace(L)
.beginNamespace("aquad")
...
.endNamespace();
Classes
Let’s show how to bind a new class on an example.
Say we have a new class MyLovelyClass
that inherits from a LogicalVolume
class.
First, find the logvol
namespace.
You will see that the first class there is binding the LogicalVolume
class.
This is also the parent class of our new class.
We add a new section for binding our new class (typically at the end of the namespace block before the .endNamespace()
call).
.deriveClass<MyLovelyClass, LogicalVolume>("MyLovelyClass")
.endClass()
.beginClass<std::shared_ptr<MyLovelyClass>>("MyLovelyClassPtr")
.endClass()
This is the basic binding for a class and should be self-explanatory.
The second part of this block is for binding a shared pointer to the class and is essential for the correct operation of the scripts.
Member functions
To bind a member function of a class, we use the following syntax:
.deriveClass<MyLovelyClass, LogicalVolume>("MyLovelyClass")
.addFunction("myFunction", &MyLovelyClass::myFunction)
.endClass()
To bind a static member function of a class, use the following syntax:
.deriveClass<MyLovelyClass, LogicalVolume>("MyLovelyClass")
.addStaticFunction("myStaticFunction", &MyLovelyClass::myStaticFunction)
.endClass()
If our class was using InputParameters
for construction, this would be the syntax we would use for binding of the Create
method.
Classes as Parameters
If our class would be used inside a Lua table (this is how InputParameters
are represented in Lua),
then we need to teach the parsing code how to construct such a class.
This is done in lua/lib/parse_table.cc
in the SetBlockParam
function.
We find the section for contructing logical volumes and add the following code:
else if (cls_name == "MyLovelyClass")
block.AddParameter(key, CreateObjectPtr<opensn::LogicalVolume>(L));
Member variables
Public member variables can be bound into Lua as properties.
Let’s see an example how it is done on the Vector3
class.
luabridge::getGlobalNamespace(L)
.beginClass<Vector3>("Vector3")
...
.addProperty("x", &Vector3::x)
.addProperty("y", &Vector3::y)
.addProperty("z", &Vector3::z)
...
.endClass();
Enums
Lua does not have an enum type, so we need to bind enum values as variables.
For example, if we had an enum:
enum MyEnum {
VALUE1,
VALUE2,
VALUE3
};
The binding code would look like this:
luabridge::getGlobalNamespace(L)
.addVariable("VALUE1", MyEnum::VALUE1)
.addVariable("VALUE2", MyEnum::VALUE2)
.addVariable("VALUE3", MyEnum::VALUE3);
More details
For more details see the documentation of LuaBridge3