Program Listing for File GeneralKModels_Py.cc

Program Listing for File GeneralKModels_Py.cc#

Return to documentation for file (doxygen_docs/GeneralKModels/GeneralKModels_Py.cc)

#include "GeneralKModels_Py_doc.h"
#include "Karana/GeneralKModels/ComputedTorque.h"
#include "Karana/GeneralKModels/DataLogger.h"
#include "Karana/GeneralKModels/DataPlotter.h"
#include "Karana/GeneralKModels/GraphicalSceneMovie.h"
#include "Karana/GeneralKModels/Gravity.h"
#include "Karana/GeneralKModels/GravityInterface.h"
#include "Karana/GeneralKModels/PID.h"
#include "Karana/GeneralKModels/PinJointLimits.h"
#include "Karana/GeneralKModels/ProjectConstraintError.h"
#include "Karana/GeneralKModels/SpringDamper.h"
#include "Karana/GeneralKModels/SubhingeForceLimits.h"
#include "Karana/GeneralKModels/SubhingeSpringDamper.h"
#include "Karana/GeneralKModels/SyncRealTime.h"
#include "Karana/GeneralKModels/TimeDisplay.h"
#include "Karana/GeneralKModels/UpdateProxyScene.h"
#include "Karana/KCore/pybind11Utils.h"
#include "Karana/KCore/pybind11_chrono_numpy.h"
#include "Karana/Math/Defs.h"
#include "Karana/SOADyn/pybind11KModel.h"
#include <pybind11/eigen.h>
#include <pybind11/functional.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/typing.h>

/**
 * @file
 * @brief Python bindings for GeneralKModels.
 */

namespace py = pybind11;

namespace kc = Karana::Core;
using namespace Karana::Models;

ADD_TO_DS_METHOD_CASTER(SpringDamper, Karana.Models.GeneralKModels_types, SpringDamperDS)
ADD_TO_DS_METHOD_CASTER(GravityInterface, Karana.Models.GeneralKModels_types, GravityInterfaceDS)
ADD_TO_DS_METHOD_CASTER(PointMassGravity, Karana.Models.GeneralKModels_types, PointMassGravityDS)
ADD_TO_DS_METHOD_CASTER(UniformGravity, Karana.Models.GeneralKModels_types, UniformGravityDS)
ADD_TO_DS_METHOD_CASTER(Gravity, Karana.Models.GeneralKModels_types, GravityDS)
ADD_TO_DS_METHOD_CASTER(UpdateProxyScene, Karana.Models.GeneralKModels_types, UpdateProxySceneDS)
ADD_TO_DS_METHOD_CASTER(SyncRealTime, Karana.Models.GeneralKModels_types, SyncRealTimeDS)

PYBIND11_MODULE(_GeneralKModels_Py, m) {

    py::module::import("Karana.Dynamics._SOADyn_Py");

    py::class_<GravityOutput>(m, "GravityOutput", DOC(Karana, Models, GravityOutput))
        .def_readwrite("g", &GravityOutput::g)
        .def_readwrite("t", &GravityOutput::t)
        .def_readwrite("update_type", &GravityOutput::update_type);

    py::class_<GravityInterface, kc::Base, kc::ks_ptr<GravityInterface>> PyGravityInterface(
        m, "GravityInterface", DOC(Karana, Models, GravityInterface));

    PyGravityInterface
        .def("getGravity",
             &GravityInterface::getGravity,
             DOC(Karana, Models, GravityInterface, getGravity))
        .def("setGravity",
             &GravityInterface::setGravity,
             py::arg("g"),
             py::arg("t"),
             py::arg("output_update_type"),
             DOC(Karana, Models, GravityInterface, setGravity))
        .def("isReady", &GravityInterface::isReady, DOC(Karana, Models, GravityInterface, isReady));

    addToDSMethod<GravityInterface>(PyGravityInterface,
                                    "GravityInterface",
                                    "Karana.Models.GeneralKModels_types",
                                    "GravityInterface",
                                    "fromGravityInterface");

    py::class_<UniformGravity, GravityInterface, kc::ks_ptr<UniformGravity>> PyUniformGravity(
        m, "UniformGravity", DOC(Karana, Models, UniformGravity));

    PyUniformGravity
        .def(py::init<>(&UniformGravity::create),
             py::arg("name"),
             DOC(Karana, Models, UniformGravity, create))
        .def_static("create",
                    &UniformGravity::create,
                    py::arg("name"),
                    DOC(Karana, Models, UniformGravity, create))
        .def("__deepcopy__",
             [](kc::ks_ptr<UniformGravity> &self, py::object /*memo*/) { return self; });

    addToDSMethod<UniformGravity>(PyUniformGravity,
                                  "UniformGravity",
                                  "Karana.Models.GeneralKModels_types",
                                  "UniformGravityDS",
                                  "fromGravityInterface");

    py::class_<PointMassGravity, GravityInterface, kc::ks_ptr<PointMassGravity>> PyPointMassGravity(
        m, "PointMassGravity", DOC(Karana, Models, PointMassGravity));

    PyPointMassGravity
        .def(py::init<>(&PointMassGravity::create),
             py::arg("name"),
             py::arg("st"),
             py::arg("central_body"),
             DOC(Karana, Models, PointMassGravity, create))
        .def_static("create",
                    &PointMassGravity::create,
                    py::arg("name"),
                    py::arg("st"),
                    py::arg("central_body"),
                    DOC(Karana, Models, PointMassGravity, create))
        .def_readwrite("mu", &PointMassGravity::mu, DOC(Karana, Models, PointMassGravity, mu))
        .def("getObjIds",
             &PointMassGravity::getObjIds,
             DOC(Karana, Models, PointMassGravity, getObjIds))
        .def("__deepcopy__",
             [](kc::ks_ptr<PointMassGravity> &self, py::object /*memo*/) { return self; });

    addToDSMethod<PointMassGravity>(PyPointMassGravity,
                                    "PointMassGravity",
                                    "Karana.Models.GeneralKModels_types",
                                    "PointMassGravityDS",
                                    "fromGravityInterface");

    auto PyKmodelUniformGrav = KModelPybind11<Gravity>("GravityKModel", m);

    py::class_<Gravity, KModel<Gravity>, kc::ks_ptr<Gravity>>(
        m, "Gravity", DOC(Karana, Models, Gravity))
        .def(py::init<>(&Gravity::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("gravity_interface"),
             py::arg("st"),
             DOC(Karana, Models, Gravity, create))
        .def_static("create",
                    &Gravity::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("gravity_interface"),
                    py::arg("st"),
                    DOC(Karana, Models, Gravity, create))
        .def("preDeriv",
             &Gravity::preDeriv,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, Gravity, preDeriv))
        .def("getGravityInterface",
             &Gravity::getGravityInterface,
             DOC(Karana, Models, Gravity, getGravityInterface));

    addToDSMethod<Gravity>(PyKmodelUniformGrav,
                           "Gravity",
                           "Karana.Models.GeneralKModels_types",
                           "GravityDS",
                           "fromModel");

    py::class_<ProfileGenerator<double>, kc::Base, kc::ks_ptr<ProfileGenerator<double>>>
        PyFloatProfileGenerator(m, "FloatProfileGenerator", DOC(Karana, Models, ProfileGenerator));

    PyFloatProfileGenerator.def("getValue",
                                &ProfileGenerator<double>::getValue,
                                py::arg("t"),
                                DOC(Karana, Models, ProfileGenerator, getValue));

    py::class_<ProfileGenerator<km::Vec>, kc::Base, kc::ks_ptr<ProfileGenerator<km::Vec>>>
        PyVecProfileGenerator(m, "VecProfileGenerator", DOC(Karana, Models, ProfileGenerator));

    PyVecProfileGenerator.def("getValue",
                              &ProfileGenerator<km::Vec>::getValue,
                              py::arg("t"),
                              DOC(Karana, Models, ProfileGenerator, getValue));

    py::class_<ProfileGenerator<km::UnitQuaternion>,
               kc::Base,
               kc::ks_ptr<ProfileGenerator<km::UnitQuaternion>>>
        PyUnitQuaternionProfileGenerator(
            m, "UnitQuaternionProfileGenerator", DOC(Karana, Models, ProfileGenerator));

    PyUnitQuaternionProfileGenerator.def("getValue",
                                         &ProfileGenerator<km::UnitQuaternion>::getValue,
                                         py::arg("t"),
                                         DOC(Karana, Models, ProfileGenerator, getValue));

    py::class_<LinearProfileGenerator<double>,
               ProfileGenerator<double>,
               kc::ks_ptr<LinearProfileGenerator<double>>>
        PyFloatLinearProfileGenerator(
            m, "FloatLinearProfileGenerator", DOC(Karana, Models, LinearProfileGenerator));

    PyFloatLinearProfileGenerator
        .def(py::init<>(&LinearProfileGenerator<double>::create),
             py::arg("name"),
             py::arg("t_i"),
             py::arg("value_i"),
             py::arg("t_f"),
             py::arg("value_f"),
             DOC(Karana, Models, LinearProfileGenerator, create))
        .def_static("create",
                    &LinearProfileGenerator<double>::create,
                    py::arg("name"),
                    py::arg("t_i"),
                    py::arg("value_i"),
                    py::arg("t_f"),
                    py::arg("value_f"),
                    DOC(Karana, Models, LinearProfileGenerator, create))
        .def_readwrite("t_i", &LinearProfileGenerator<double>::t_i)
        .def_readwrite("t_f", &LinearProfileGenerator<double>::t_f)
        .def_readwrite("value_i", &LinearProfileGenerator<double>::value_i)
        .def_readwrite("value_f", &LinearProfileGenerator<double>::value_f);

    py::class_<LinearProfileGenerator<km::Vec>,
               ProfileGenerator<km::Vec>,
               kc::ks_ptr<LinearProfileGenerator<km::Vec>>>
        PyVecLinearProfileGenerator(
            m, "VecLinearProfileGenerator", DOC(Karana, Models, LinearProfileGenerator));

    PyVecLinearProfileGenerator
        .def(py::init<>(&LinearProfileGenerator<km::Vec>::create),
             py::arg("name"),
             py::arg("t_i"),
             py::arg("value_i"),
             py::arg("t_f"),
             py::arg("value_f"),
             DOC(Karana, Models, LinearProfileGenerator, create))
        .def_static("create",
                    &LinearProfileGenerator<km::Vec>::create,
                    py::arg("name"),
                    py::arg("t_i"),
                    py::arg("value_i"),
                    py::arg("t_f"),
                    py::arg("value_f"),
                    DOC(Karana, Models, LinearProfileGenerator, create))
        .def_readwrite("t_i", &LinearProfileGenerator<km::Vec>::t_i)
        .def_readwrite("t_f", &LinearProfileGenerator<km::Vec>::t_f)
        .def_readwrite("value_i", &LinearProfileGenerator<km::Vec>::value_i)
        .def_readwrite("value_f", &LinearProfileGenerator<km::Vec>::value_f);

    py::class_<ConstantProfileGenerator<double>,
               ProfileGenerator<double>,
               kc::ks_ptr<ConstantProfileGenerator<double>>>
        PyFloatConstantProfileGenerator(
            m, "FloatConstantProfileGenerator", DOC(Karana, Models, ConstantProfileGenerator));

    PyFloatConstantProfileGenerator
        .def(py::init<>(&ConstantProfileGenerator<double>::create),
             py::arg("name"),
             py::arg("value"),
             DOC(Karana, Models, ConstantProfileGenerator, create))
        .def_static("create",
                    &ConstantProfileGenerator<double>::create,
                    py::arg("name"),
                    py::arg("value"),
                    DOC(Karana, Models, ConstantProfileGenerator, create))
        .def_readwrite("value", &ConstantProfileGenerator<double>::value);

    py::class_<ConstantProfileGenerator<km::Vec>,
               ProfileGenerator<km::Vec>,
               kc::ks_ptr<ConstantProfileGenerator<km::Vec>>>
        PyVecConstantProfileGenerator(
            m, "VecConstantProfileGenerator", DOC(Karana, Models, ConstantProfileGenerator));

    PyVecConstantProfileGenerator
        .def(py::init<>(&ConstantProfileGenerator<km::Vec>::create),
             py::arg("name"),
             py::arg("value"),
             DOC(Karana, Models, ConstantProfileGenerator, create))
        .def_static("create",
                    &ConstantProfileGenerator<km::Vec>::create,
                    py::arg("name"),
                    py::arg("value"),
                    DOC(Karana, Models, ConstantProfileGenerator, create))
        .def_readwrite("value", &ConstantProfileGenerator<km::Vec>::value);

    py::class_<ConstantProfileGenerator<km::UnitQuaternion>,
               ProfileGenerator<km::UnitQuaternion>,
               kc::ks_ptr<ConstantProfileGenerator<km::UnitQuaternion>>>
        PyUnitQuaternionConstantProfileGenerator(m,
                                                 "UnitQuaternionConstantProfileGenerator",
                                                 DOC(Karana, Models, ConstantProfileGenerator));

    PyUnitQuaternionConstantProfileGenerator
        .def(py::init<>(&ConstantProfileGenerator<km::UnitQuaternion>::create),
             py::arg("name"),
             py::arg("value"),
             DOC(Karana, Models, ConstantProfileGenerator, create))
        .def_static("create",
                    &ConstantProfileGenerator<km::UnitQuaternion>::create,
                    py::arg("name"),
                    py::arg("value"),
                    DOC(Karana, Models, ConstantProfileGenerator, create))
        .def_readwrite("value", &ConstantProfileGenerator<km::UnitQuaternion>::value);

    py::class_<SpringDamperParams, kc::ks_ptr<SpringDamperParams>>(
        m, "SpringDamperParams", DOC(Karana, Models, SpringDamperParams))
        .def("isReady",
             &SpringDamperParams::isReady,
             DOC(Karana, Models, SpringDamperParams, isReady))
        .def_readwrite("unsprung_length",
                       &SpringDamperParams::unsprung_length,
                       DOC(Karana, Models, SpringDamperParams, unsprung_length))
        .def_readwrite("d", &SpringDamperParams::d, DOC(Karana, Models, SpringDamperParams, d))
        .def_readwrite("k", &SpringDamperParams::k, DOC(Karana, Models, SpringDamperParams, k));

    py::class_<SpringDamperScratch, kc::ks_ptr<SpringDamperScratch>>(
        m, "SpringDamperScratch", DOC(Karana, Models, SpringDamperScratch))
        .def_readwrite("offset",
                       &SpringDamperScratch::offset,
                       DOC(Karana, Models, SpringDamperScratch, offset))
        .def_readwrite("position_error",
                       &SpringDamperScratch::position_error,
                       DOC(Karana, Models, SpringDamperScratch, position_error))
        .def_readwrite("velocity_error",
                       &SpringDamperScratch::velocity_error,
                       DOC(Karana, Models, SpringDamperScratch, velocity_error))
        .def_readwrite("stiffness_force",
                       &SpringDamperScratch::stiffness_force,
                       DOC(Karana, Models, SpringDamperScratch, stiffness_force))
        .def_readwrite("damping_force",
                       &SpringDamperScratch::damping_force,
                       DOC(Karana, Models, SpringDamperScratch, damping_force))
        .def_readwrite("total_force",
                       &SpringDamperScratch::total_force,
                       DOC(Karana, Models, SpringDamperScratch, total_force));

    auto PyKmodelSpringDamper =
        KModelPybind11<SpringDamper, SpringDamperParams, SpringDamperScratch>("SpringDamperKModel",
                                                                              m);

    py::class_<SpringDamper,
               KModel<SpringDamper, SpringDamperParams, SpringDamperScratch>,
               kc::ks_ptr<SpringDamper>>
        PySpringDamper(m, "SpringDamper", DOC(Karana, Models, SpringDamper));

    PySpringDamper
        .def(py::init<>(&SpringDamper::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("nd1"),
             py::arg("nd2"),
             DOC(Karana, Models, SpringDamper, create))
        .def_static("create",
                    &SpringDamper::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("nd1"),
                    py::arg("nd2"),
                    DOC(Karana, Models, SpringDamper, create))
        .def("preDeriv",
             &SpringDamper::preDeriv,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, SpringDamper, preDeriv))
        .def("sourceNode", &SpringDamper::sourceNode, DOC(Karana, Models, SpringDamper, sourceNode))
        .def(
            "targetNode", &SpringDamper::targetNode, DOC(Karana, Models, SpringDamper, targetNode));

    addToDSMethod<SpringDamper>(PySpringDamper,
                                "SpringDamper",
                                "Karana.Models.GeneralKModels_types",
                                "SpringDamperDS",
                                "fromModel");

    py::class_<PinJointLimitsParams, kc::ks_ptr<PinJointLimitsParams>>(
        m, "PinJointLimitsParams", DOC(Karana, Models, PinJointLimitsParams))
        .def("isReady",
             &PinJointLimitsParams::isReady,
             DOC(Karana, Models, PinJointLimitsParams, isReady))
        .def_readwrite("upper_limit",
                       &PinJointLimitsParams::upper_limit,
                       DOC(Karana, Models, PinJointLimitsParams, upper_limit))
        .def_readwrite("lower_limit",
                       &PinJointLimitsParams::lower_limit,
                       DOC(Karana, Models, PinJointLimitsParams, lower_limit))
        .def_readwrite("d", &PinJointLimitsParams::d, DOC(Karana, Models, PinJointLimitsParams, d))
        .def_readwrite("k", &PinJointLimitsParams::k, DOC(Karana, Models, PinJointLimitsParams, k));

    auto PyKmodelPinJointLimits =
        KModelPybind11<PinJointLimits, PinJointLimitsParams>("PinJointLimitsKModel", m);

    py::class_<PinJointLimits,
               KModel<PinJointLimits, PinJointLimitsParams>,
               kc::ks_ptr<PinJointLimits>>(m, "PinJointLimits", DOC(Karana, Models, PinJointLimits))
        .def(py::init<>(&PinJointLimits::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("pin"),
             DOC(Karana, Models, PinJointLimits, create))
        .def_static("create",
                    &PinJointLimits::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("pin"),
                    DOC(Karana, Models, PinJointLimits, create))
        .def("preDeriv",
             &PinJointLimits::preDeriv,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, PinJointLimits, preDeriv));

    py::class_<SubhingeSpringDamperParams, kc::ks_ptr<SubhingeSpringDamperParams>>(
        m, "SubhingeSpringDamperParams", DOC(Karana, Models, SubhingeSpringDamperParams))
        .def("isReady",
             &SubhingeSpringDamperParams::isReady,
             DOC(Karana, Models, SubhingeSpringDamperParams, isReady))
        .def_readwrite("setpoint",
                       &SubhingeSpringDamperParams::setpoint,
                       DOC(Karana, Models, SubhingeSpringDamperParams, setpoint))
        .def_readwrite(
            "d", &SubhingeSpringDamperParams::d, DOC(Karana, Models, SubhingeSpringDamperParams, d))
        .def_readwrite("k",
                       &SubhingeSpringDamperParams::k,
                       DOC(Karana, Models, SubhingeSpringDamperParams, k));

    auto PyKmodelSubhingeSpringDamper =
        KModelPybind11<SubhingeSpringDamper, SubhingeSpringDamperParams>(
            "SubhingeSpringDamperKModel", m);

    py::class_<SubhingeSpringDamper,
               KModel<SubhingeSpringDamper, SubhingeSpringDamperParams>,
               kc::ks_ptr<SubhingeSpringDamper>>(
        m, "SubhingeSpringDamper", DOC(Karana, Models, SubhingeSpringDamper))
        .def(py::init<>(&SubhingeSpringDamper::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("sh"),
             DOC(Karana, Models, SubhingeSpringDamper, create))
        .def_static("create",
                    &SubhingeSpringDamper::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("sh"),
                    DOC(Karana, Models, SubhingeSpringDamper, create))
        .def("preDeriv",
             &SubhingeSpringDamper::preDeriv,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, SubhingeSpringDamper, preDeriv));

    py::class_<SubhingeForceLimitsParams, kc::ks_ptr<SubhingeForceLimitsParams>>(
        m, "SubhingeForceLimitsParams", DOC(Karana, Models, SubhingeForceLimitsParams))
        .def("isReady",
             &SubhingeForceLimitsParams::isReady,
             DOC(Karana, Models, SubhingeForceLimitsParams, isReady))
        .def_readwrite("lower_limits",
                       &SubhingeForceLimitsParams::lower_limits,
                       DOC(Karana, Models, SubhingeForceLimitsParams, lower_limits))
        .def_readwrite("upper_limits",
                       &SubhingeForceLimitsParams::upper_limits,
                       DOC(Karana, Models, SubhingeForceLimitsParams, upper_limits));

    auto PyKmodelSubhingeForceLimits =
        KModelPybind11<SubhingeForceLimits, SubhingeForceLimitsParams>("SubhingeForceLimitsKModel",
                                                                       m);

    py::class_<SubhingeForceLimits,
               KModel<SubhingeForceLimits, SubhingeForceLimitsParams>,
               kc::ks_ptr<SubhingeForceLimits>>(
        m, "SubhingeForceLimits", DOC(Karana, Models, SubhingeForceLimits))
        .def(py::init<>(&SubhingeForceLimits::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("sh"),
             DOC(Karana, Models, SubhingeForceLimits, create))
        .def_static("create",
                    &SubhingeForceLimits::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("sh"),
                    DOC(Karana, Models, SubhingeForceLimits, create))
        .def("preDeriv",
             &SubhingeForceLimits::preDeriv,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, SubhingeForceLimits, preDeriv));

    py::class_<PIDParams, kc::ks_ptr<PIDParams>>(m, "PIDParams", DOC(Karana, Models, PIDParams))
        .def("isReady", &PIDParams::isReady, DOC(Karana, Models, PIDParams, isReady))
        .def_readwrite("kp", &PIDParams::kp, DOC(Karana, Models, PIDParams, kp))
        .def_readwrite("kd", &PIDParams::kd, DOC(Karana, Models, PIDParams, kd))
        .def_readwrite("ki", &PIDParams::ki, DOC(Karana, Models, PIDParams, ki));

    auto PyKmodelPID = KModelPybind11<PID, PIDParams>("PIDKModel", m);

    py::class_<PID, KModel<PID, PIDParams>, kc::ks_ptr<PID>>(m, "PID", DOC(Karana, Models, PID))
        .def(py::init<>(&PID::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("sh"),
             py::arg("q_traj"),
             py::arg("u_traj"),
             DOC(Karana, Models, PID, create))
        .def_static("create",
                    &PID::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("sh"),
                    py::arg("q_traj"),
                    py::arg("u_traj"),
                    DOC(Karana, Models, PID, create))
        .def("preModelStep",
             &PID::preModelStep,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, PID, preModelStep))
        .def("preDeriv",
             &PID::preDeriv,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, PID, preDeriv))
        .def_readwrite("q_traj", &PID::q_traj)
        .def_readwrite("u_traj", &PID::u_traj);

    auto PyKmodelUpdateProxyScene = KModelPybind11<UpdateProxyScene>("UpdateProxySceneKModel", m);

    py::class_<UpdateProxyScene, KModel<UpdateProxyScene>, kc::ks_ptr<UpdateProxyScene>>
        PyUpdateProxyScene(m, "UpdateProxyScene", DOC(Karana, Models, UpdateProxyScene));

    PyUpdateProxyScene
        .def(py::init<>(&UpdateProxyScene::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("scene"),
             DOC(Karana, Models, UpdateProxyScene, create))
        .def_static("create",
                    &UpdateProxyScene::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("scene"),
                    DOC(Karana, Models, UpdateProxyScene, create))
        .def("postHop",
             &UpdateProxyScene::postHop,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, UpdateProxyScene, postHop))
        .def("getProxyScene",
             &UpdateProxyScene::getProxyScene,
             DOC(Karana, Models, UpdateProxyScene, getProxyScene));

    addToDSMethod<UpdateProxyScene>(PyUpdateProxyScene,
                                    "UpdateProxyScene",
                                    "Karana.Models.GeneralKModels_types",
                                    "UpdateProxySceneDS",
                                    "fromModel");

    auto PyKmodelSyncRealTime = KModelPybind11<SyncRealTime>("SyncRealTimeKModel", m);

    py::class_<SyncRealTime, KModel<SyncRealTime>, kc::ks_ptr<SyncRealTime>> PySyncRealTime(
        m, "SyncRealTime", DOC(Karana, Models, SyncRealTime));

    PySyncRealTime
        .def(py::init<>(&SyncRealTime::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("rt_speed") = 1.0,
             DOC(Karana, Models, SyncRealTime, create))
        .def_static("create",
                    &SyncRealTime::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("rt_speed") = 1.0,
                    DOC(Karana, Models, SyncRealTime, create))
        .def("preHop",
             &SyncRealTime::preHop,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, SyncRealTime, preHop))
        .def("postHop",
             &SyncRealTime::postHop,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, SyncRealTime, postHop))
        .def("getRealTimeSpeed",
             &SyncRealTime::getRealTimeSpeed,
             DOC(Karana, Models, SyncRealTime, getRealTimeSpeed));

    addToDSMethod<SyncRealTime>(PySyncRealTime,
                                "SyncRealTime",
                                "Karana.Models.GeneralKModels_types",
                                "SyncRealTimeDS",
                                "fromModel");

    py::class_<TimeDisplayParams, kc::ks_ptr<TimeDisplayParams>>(
        m, "TimeDisplayParams", DOC(Karana, Models, TimeDisplayParams))
        .def(
            "isReady", &TimeDisplayParams::isReady, DOC(Karana, Models, TimeDisplayParams, isReady))
        .def_readwrite(
            "color", &TimeDisplayParams::color, DOC(Karana, Models, TimeDisplayParams, color));

    auto PyKmodelTimeDisplay =
        KModelPybind11<TimeDisplay, TimeDisplayParams>("TimeDisplayKModel", m);

    py::class_<TimeDisplay, KModel<TimeDisplay, TimeDisplayParams>, kc::ks_ptr<TimeDisplay>>(
        m, "TimeDisplay", DOC(Karana, Models, TimeDisplay))
        .def(py::init<>(&TimeDisplay::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("scene"),
             DOC(Karana, Models, TimeDisplay, create))
        .def_static("create",
                    &TimeDisplay::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("scene"),
                    DOC(Karana, Models, TimeDisplay, create))
        .def("postModelStep",
             &TimeDisplay::postModelStep,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, TimeDisplay, postModelStep));

    py::class_<GraphicalSceneMovieParams, kc::ks_ptr<GraphicalSceneMovieParams>>(
        m, "GraphicalSceneMovieParams", DOC(Karana, Models, GraphicalSceneMovieParams))
        .def("isReady",
             &GraphicalSceneMovieParams::isReady,
             DOC(Karana, Models, GraphicalSceneMovieParams, isReady))
        .def_readwrite("dir",
                       &GraphicalSceneMovieParams::dir,
                       DOC(Karana, Models, GraphicalSceneMovieParams, dir))
        .def_readwrite("filename_prefix",
                       &GraphicalSceneMovieParams::filename_prefix,
                       DOC(Karana, Models, GraphicalSceneMovieParams, filename_prefix));

    auto PyKmodelGraphicalSceneMovie =
        KModelPybind11<GraphicalSceneMovie, GraphicalSceneMovieParams>("GraphicalSceneMovieKModel",
                                                                       m);

    py::class_<GraphicalSceneMovie,
               KModel<GraphicalSceneMovie, GraphicalSceneMovieParams>,
               kc::ks_ptr<GraphicalSceneMovie>>(
        m, "GraphicalSceneMovie", DOC(Karana, Models, GraphicalSceneMovie))
        .def(py::init<>(&GraphicalSceneMovie::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("scene"),
             DOC(Karana, Models, GraphicalSceneMovie, create))
        .def_static("create",
                    &GraphicalSceneMovie::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("scene"),
                    DOC(Karana, Models, GraphicalSceneMovie, create))
        .def("postModelStep",
             &GraphicalSceneMovie::postModelStep,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, GraphicalSceneMovie, postModelStep))
        .def("getFfmpegCommand",
             &GraphicalSceneMovie::getFfmpegCommand,
             DOC(Karana, Models, GraphicalSceneMovie, getFfmpegCommand));

    py::class_<ProjectConstraintErrorParams, kc::ks_ptr<ProjectConstraintErrorParams>>(
        m, "ProjectConstraintErrorParams", DOC(Karana, Models, ProjectConstraintErrorParams))
        .def("isReady",
             &ProjectConstraintErrorParams::isReady,
             DOC(Karana, Models, ProjectConstraintErrorParams, isReady))
        .def_readwrite("tol",
                       &ProjectConstraintErrorParams::tol,
                       DOC(Karana, Models, ProjectConstraintErrorParams, tol));

    auto PyKmodelProjectConstraintError =
        KModelPybind11<ProjectConstraintError, ProjectConstraintErrorParams>(
            "ProjectConstraintErrorKModel", m);

    py::class_<ProjectConstraintError,
               KModel<ProjectConstraintError, ProjectConstraintErrorParams>,
               kc::ks_ptr<ProjectConstraintError>>(
        m, "ProjectConstraintError", DOC(Karana, Models, ProjectConstraintError))
        .def(py::init<>(&ProjectConstraintError::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("sg"),
             py::arg("integrator"),
             py::arg("cks"),
             DOC(Karana, Models, ProjectConstraintError, create))
        .def_static("create",
                    &ProjectConstraintError::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("sg"),
                    py::arg("integrator"),
                    py::arg("cks"),
                    DOC(Karana, Models, ProjectConstraintError, create))
        .def("postModelStep",
             &ProjectConstraintError::postModelStep,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, ProjectConstraintError, postModelStep));

    py::class_<DataLoggerParams, kc::ks_ptr<DataLoggerParams>>(
        m, "DataLoggerParams", DOC(Karana, Models, DataLoggerParams))
        .def("isReady", &DataLoggerParams::isReady, DOC(Karana, Models, DataLoggerParams, isReady))
        .def_readwrite("log_first_step",
                       &DataLoggerParams::log_first_step,
                       DOC(Karana, Models, DataLoggerParams, log_first_step));

    auto PyKmodelDataLogger = KModelPybind11<DataLogger, DataLoggerParams>("DataLoggerKModel", m);

    py::class_<DataLogger, KModel<DataLogger, DataLoggerParams>, kc::ks_ptr<DataLogger>>(
        m, "DataLogger", DOC(Karana, Models, DataLogger))
        .def(py::init<>(&DataLogger::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("h5_writer"),
             DOC(Karana, Models, DataLogger, create))
        .def_static("create",
                    &DataLogger::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("h5_writer"),
                    DOC(Karana, Models, DataLogger, create))
        .def("postModelStep",
             &DataLogger::postModelStep,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, DataLogger, postModelStep))
        .def("getH5Writer", &DataLogger::getH5Writer, DOC(Karana, Models, DataLogger, getH5Writer));

    py::class_<DataPlotterParams, kc::ks_ptr<DataPlotterParams>>(
        m, "DataPlotterParams", DOC(Karana, Models, DataPlotterParams))
        .def(
            "isReady", &DataPlotterParams::isReady, DOC(Karana, Models, DataPlotterParams, isReady))
        .def_readwrite("log_first_step",
                       &DataPlotterParams::log_first_step,
                       DOC(Karana, Models, DataPlotterParams, log_first_step));

    auto PyKmodelDataPlotter =
        KModelPybind11<DataPlotter, DataPlotterParams>("DataPlotterKModel", m);

    py::class_<DataPlotter, KModel<DataPlotter, DataPlotterParams>, kc::ks_ptr<DataPlotter>>(
        m, "DataPlotter", DOC(Karana, Models, DataPlotter))
        .def(py::init<>(&DataPlotter::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("plot_data"),
             DOC(Karana, Models, DataPlotter, create))
        .def_static("create",
                    &DataPlotter::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("plot_data"),
                    DOC(Karana, Models, DataPlotter, create))
        .def("postModelStep",
             &DataPlotter::postModelStep,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, DataPlotter, postModelStep))
        .def("getPlotData",
             &DataPlotter::getPlotData,
             DOC(Karana, Models, DataPlotter, getPlotData));

    auto PyKmodelComputedTorque = KModelPybind11<ComputedTorque>("ComputedTorqueKModel", m);

    py::class_<ComputedTorque, KModel<ComputedTorque>, kc::ks_ptr<ComputedTorque>>(
        m, "ComputedTorque", DOC(Karana, Models, ComputedTorque))
        .def(py::init<>(&ComputedTorque::create),
             py::arg("name"),
             py::arg("mm"),
             py::arg("st"),
             py::arg("set_accels_fn"),
             DOC(Karana, Models, ComputedTorque, create))
        .def_static("create",
                    &ComputedTorque::create,
                    py::arg("name"),
                    py::arg("mm"),
                    py::arg("st"),
                    py::arg("set_accels_fn"),
                    DOC(Karana, Models, ComputedTorque, create))
        .def("preDeriv",
             &ComputedTorque::preDeriv,
             py::arg("t"),
             py::arg("x"),
             DOC(Karana, Models, ComputedTorque, preDeriv));
}