Program Listing for File pybind11KModel.h

Program Listing for File pybind11KModel.h#

Return to documentation for file (include/Karana/SOADyn/pybind11KModel.h)

/*
 * Copyright (c) 2024-2026 Karana Dynamics Pty Ltd. All rights reserved.
 *
 * NOTICE TO USER:
 *
 * This source code and/or documentation (the "Licensed Materials") is
 * the confidential and proprietary information of Karana Dynamics Inc.
 * Use of these Licensed Materials is governed by the terms and conditions
 * of a separate software license agreement between Karana Dynamics and the
 * Licensee ("License Agreement"). Unless expressly permitted under that
 * agreement, any reproduction, modification, distribution, or disclosure
 * of the Licensed Materials, in whole or in part, to any third party
 * without the prior written consent of Karana Dynamics is strictly prohibited.
 *
 * THE LICENSED MATERIALS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
 * KARANA DYNAMICS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, AND
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * IN NO EVENT SHALL KARANA DYNAMICS BE LIABLE FOR ANY DAMAGES WHATSOEVER,
 * INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS, DATA, OR USE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, WHETHER IN CONTRACT, TORT,
 * OR OTHERWISE ARISING OUT OF OR IN CONNECTION WITH THE LICENSED MATERIALS.
 *
 * U.S. Government End Users: The Licensed Materials are a "commercial item"
 * as defined at 48 C.F.R. 2.101, and are provided to the U.S. Government
 * only as a commercial end item under the terms of this license.
 *
 * Any use of the Licensed Materials in individual or commercial software must
 * include, in the user documentation and internal source code comments,
 * this Notice, Disclaimer, and U.S. Government Use Provision.
 */

/**
 * @file
 * @brief Helper functions to generate pybind11 bindings for KModels.
 */

#include "Karana/KCore/pybind11_chrono_numpy.h"
#include "Karana/SOADyn/KModel.h"
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

namespace py = pybind11;

namespace Karana::Models {

    /**
     * @brief Create pybind11 bindings for the provided KModel.
     *
     * @tparam T The KModel class to provide bindings for.
     * @tparam P The Params class, if applicable.
     * @tparam Sc The Scratch class, if applicable.
     * @tparam S The DiscreteStates class, if applicable.
     * @tparam C The ContinuousStates class, if applicable.
     * @param class_name The name for the class in Python.
     * @param m The pybind11 module to add the class to.
     * @return The pybind11::class_ for this KModel.
     */
    template <class T,
              class P = NoParams,
              class Sc = NoScratch,
              class S = NoDiscreteStates,
              class C = NoContinuousStates>
    auto KModelPybind11( // NOLINT(readability-identifier-naming)
        const std::string &class_name,
        py::module &m) {
        auto PyKModelClass =
            py::class_<KModel<T, P, Sc, S, C>, BaseKModel, kc::ks_ptr<KModel<T, P, Sc, S, C>>>(
                m, class_name.c_str())
                .def("getNextModelStepTime",
                     &KModel<T, P, Sc, S, C>::getNextModelStepTime,
                     py::arg("t"),
                     R"raw(
             Get the next step time assuming the provided time `t` is a time the model has a step at.

             Parameters
             ----------
             t : Ktime
                 A time the model has a step at.

             Returns
             -------
             Ktime
                 The next model step time.
             )raw")

                .def("getPeriod",
                     &KModel<T, P, Sc, S, C>::getPeriod,
                     R"raw(
             Get the period of the model.

             If a `nextModelStepTime` method exists, this returns a warning. A model period and
             `nextModelStepTime` cannot both be defined for a model.

             Returns
             -------
             Ktime
                 The model's period.
             )raw")

                .def("setPeriod",
                     &KModel<T, P, Sc, S, C>::setPeriod,
                     py::arg("t"),
                     R"raw(
             Set the model period.

             The model period defines the period at which the model runs. There are a few cases to consider:

             1. The period is 0 and no `nextModelStepTime` method is defined. In this case, the
                `preModelStep`/`postModelStep` methods will run every time a simulation hop happens.
             2. The period is non-zero. In this case, those methods will run at the specified period.
             3. The period is 0 and a `nextModelStepTime` method is defined. Then, that method defines when the
                steps will run.

             A model period and `nextModelStepTime` cannot both be defined for a model. An error will be
             thrown if a model with `nextModelStepTime` has its period set.

             Parameters
             ----------
             t : Ktime
                 The new model period.
             )raw")

                .def("isReady",
                     &KModel<T, P, Sc, S, C>::isReady,
                     R"raw(
            Checks whether the model is ready.

            Returns
            -------
            bool:
                Returns false if the params pointer is empty or if the parameters are not finalize. Returns true otherwise.
            )raw")

                .def_readwrite("model_manager", &KModel<T, P, Sc, S, C>::model_manager)
                .def_readwrite("debug_model", &KModel<T, P, Sc, S, C>::debug_model);

        // Add params if a params class is defined
        if constexpr (not std::is_same_v<NoParams, P>) {
            PyKModelClass.def_readwrite("params", &KModel<T, P, Sc, S, C>::params);
        }

        // Add scratch if a scratch class is defined
        if constexpr (not std::is_same_v<NoScratch, Sc>) {
            PyKModelClass.def_readwrite("scratch", &KModel<T, P, Sc, S, C>::scratch);
        }

        // Add discrete states if a discrete states class is defined
        if constexpr (not std::is_same_v<NoDiscreteStates, S>) {
            PyKModelClass.def_readwrite("discrete_states",
                                        &KModel<T, P, Sc, S, C>::discrete_states);
        }

        // Add continuous_states if a continuous_states class is defined
        if constexpr (not std::is_same_v<NoContinuousStates, C>) {
            PyKModelClass.def_readwrite("continuous_states",
                                        &KModel<T, P, Sc, S, C>::continuous_states);
        }

        return PyKModelClass;
    }

} // namespace Karana::Models