Program Listing for File pybind11Kquantities.h#
↰ Return to documentation for file (include/Karana/Math/pybind11Kquantities.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.
*/
#pragma once
#include "Karana/Math/Defs.h"
#include <pybind11/eigen.h>
#include <pybind11/pybind11.h>
#include <type_traits>
#include <utility>
namespace Karana::Math {
/** Metadata for a length quantity. */
struct LengthTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.Length";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "length";
};
/** Metadata for an angle quantity. */
struct AngleTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.Angle";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "angle";
};
/** Metadata for a mass quantity. */
struct MassTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.Mass";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "mass";
};
/** Metadata for a gravitational-parameter quantity. */
struct GravitationalParameterTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.GravitationalParameter";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "gravitational_parameter";
};
/** Metadata for a linear spring constant quantity. */
struct LinearSpringConstantTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.LinearSpringConstant";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "linear_spring_constant";
};
/** Metadata for a linear damping constant quantity. */
struct LinearDampingConstantTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.LinearDampingConstant";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "linear_damping_constant";
};
/** Metadata for a velocity quantity. */
struct VelocityTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.Velocity";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "velocity";
};
/** Metadata for an angular velocity quantity. */
struct AngularVelocityTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.AngularVelocity";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "angular_velocity";
};
/** Metadata for an acceleration quantity. */
struct AccelerationTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.Acceleration";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "acceleration";
};
/** Metadata for an angular acceleration quantity. */
struct AngularAccelerationTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.AngularAcceleration";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "angular_acceleration";
};
/** Metadata for a force quantity. */
struct ForceTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.Force";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "force";
};
/** Metadata for a torque quantity. */
struct TorqueTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.Torque";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "torque";
};
/** Metadata for a momentum quantity. */
struct MomentumTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.Momentum";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "momentum";
};
/** Metadata for an angular momentum quantity. */
struct AngularMomentumTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.AngularMomentum";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "angular_momentum";
};
/** Metadata for a modal stiffness quantity. */
struct ModalStiffnessTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.ModalStiffness";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "modal_stiffness";
};
/** Metadata for a modal damping quantity. */
struct ModalDampingTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.ModalDamping";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "modal_damping";
};
/** Metadata for an inertia quantity. */
struct InertiaTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.Inertia";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "inertia";
};
/** Metadata for a translational nodal matrix quantity. */
struct TranslationalNodalMatrixTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.TranslationalNodalMatrix";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "translational_nodal_matrix";
};
/** Metadata for a rotational nodal matrix quantity. */
struct RotationalNodalMatrixTag {
/// Fully qualified Python typing name for this quantity.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.RotationalNodalMatrix";
/// Attribute name in `Karana.Math.Kquantities`.
static constexpr char quantityName[] = "rotational_nodal_matrix";
};
/**
* @struct QuantityValueTyping
* @brief Describes the Python annotation for a C++ magnitude type.
*
* The primary template preserves support for arbitrary magnitude types by
* allowing the pybind11 caster to supply its normal Python annotation.
*
* @tparam Value The C++ type used to store a quantity magnitude.
*/
template <typename Value> struct QuantityValueTyping {
/// Whether `pythonTypeName` supplies an explicit bracket annotation.
static constexpr bool hasPythonTypeName = false;
/// Whether `pythonTypeName` names a Karana Ktyping alias.
static constexpr bool hasKtypingName = false;
/// Explicit Python type name, empty when no name is registered.
static constexpr char pythonTypeName[] = "";
};
/** Python typing metadata for a double-precision scalar magnitude. */
template <> struct QuantityValueTyping<double> {
/// Whether `pythonTypeName` supplies an explicit bracket annotation.
static constexpr bool hasPythonTypeName = true;
/// Whether `pythonTypeName` names a Karana Ktyping alias.
static constexpr bool hasKtypingName = false;
/// Python annotation used inside the quantity generic type.
static constexpr char pythonTypeName[] = "float";
};
/** Ktyping metadata for a fixed-size three-vector magnitude. */
template <> struct QuantityValueTyping<Vec3> {
/// Whether `pythonTypeName` supplies an explicit bracket annotation.
static constexpr bool hasPythonTypeName = true;
/// Whether `pythonTypeName` names a Karana Ktyping alias.
static constexpr bool hasKtypingName = true;
/// Fully qualified Ktyping alias for this magnitude type.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.Vec3";
};
/** Ktyping metadata for a variable-length vector magnitude. */
template <> struct QuantityValueTyping<Vec> {
/// Whether `pythonTypeName` supplies an explicit bracket annotation.
static constexpr bool hasPythonTypeName = true;
/// Whether `pythonTypeName` names a Karana Ktyping alias.
static constexpr bool hasKtypingName = true;
/// Fully qualified Ktyping alias for this magnitude type.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.Vec";
};
/** Ktyping metadata for a fixed-size three-by-three matrix magnitude. */
template <> struct QuantityValueTyping<Mat33> {
/// Whether `pythonTypeName` supplies an explicit bracket annotation.
static constexpr bool hasPythonTypeName = true;
/// Whether `pythonTypeName` names a Karana Ktyping alias.
static constexpr bool hasKtypingName = true;
/// Fully qualified Ktyping alias for this magnitude type.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.Mat33";
};
/** Ktyping metadata for a three-by-N matrix magnitude. */
template <> struct QuantityValueTyping<Mat3n> {
/// Whether `pythonTypeName` supplies an explicit bracket annotation.
static constexpr bool hasPythonTypeName = true;
/// Whether `pythonTypeName` names a Karana Ktyping alias.
static constexpr bool hasKtypingName = true;
/// Fully qualified Ktyping alias for this magnitude type.
static constexpr char pythonTypeName[] = "Karana.Math.Ktyping.Mat3n";
};
/**
* @struct Quantity
* @brief Associates a C++ value with physical-quantity metadata for pybind11.
*
* @tparam Value The scalar, vector, or matrix type holding the magnitude.
* @tparam Tag The quantity metadata tag used to select Pint units.
*/
template <typename Value, typename Tag> struct Quantity {
/// Type holding the quantity magnitude.
using ValueType = Value;
/// Metadata tag describing the physical quantity.
using TagType = Tag;
/** @brief Default constructor used by the pybind11 caster. */
Quantity() = default;
/**
* @brief Constructs a quantity from its magnitude.
* @param magnitude The value to store.
*/
Quantity(Value magnitude)
: value(std::move(magnitude)) {}
/// The magnitude expressed as the selected value type.
Value value{};
/**
* @brief Converts to a mutable magnitude reference.
* @return The stored magnitude.
*/
operator Value &() { return value; }
/**
* @brief Converts to a constant magnitude reference.
* @return The stored magnitude.
*/
operator const Value &() const { return value; }
};
/**
* @brief Length quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using Length = Quantity<Value, LengthTag>;
/**
* @brief Angle quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using Angle = Quantity<Value, AngleTag>;
/**
* @brief Mass quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using Mass = Quantity<Value, MassTag>;
/**
* @brief Gravitational-parameter quantity with a caller-selected magnitude
* type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value>
using GravitationalParameter = Quantity<Value, GravitationalParameterTag>;
/**
* @brief Linear spring constant quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using LinearSpringConstant = Quantity<Value, LinearSpringConstantTag>;
/**
* @brief Linear damping constant quantity with a caller-selected magnitude
* type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value>
using LinearDampingConstant = Quantity<Value, LinearDampingConstantTag>;
/**
* @brief Velocity quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using Velocity = Quantity<Value, VelocityTag>;
/**
* @brief Angular velocity quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using AngularVelocity = Quantity<Value, AngularVelocityTag>;
/**
* @brief Acceleration quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using Acceleration = Quantity<Value, AccelerationTag>;
/**
* @brief Angular acceleration quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using AngularAcceleration = Quantity<Value, AngularAccelerationTag>;
/**
* @brief Force quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using Force = Quantity<Value, ForceTag>;
/**
* @brief Torque quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using Torque = Quantity<Value, TorqueTag>;
/**
* @brief Momentum quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using Momentum = Quantity<Value, MomentumTag>;
/**
* @brief Angular momentum quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using AngularMomentum = Quantity<Value, AngularMomentumTag>;
/**
* @brief Modal stiffness quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using ModalStiffness = Quantity<Value, ModalStiffnessTag>;
/**
* @brief Modal damping quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using ModalDamping = Quantity<Value, ModalDampingTag>;
/**
* @brief Inertia quantity with a caller-selected magnitude type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value> using Inertia = Quantity<Value, InertiaTag>;
/**
* @brief Translational nodal matrix quantity with a caller-selected magnitude
* type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value>
using TranslationalNodalMatrix = Quantity<Value, TranslationalNodalMatrixTag>;
/**
* @brief Rotational nodal matrix quantity with a caller-selected magnitude
* type.
* @tparam Value The type used to store the quantity magnitude.
*/
template <typename Value>
using RotationalNodalMatrix = Quantity<Value, RotationalNodalMatrixTag>;
} // namespace Karana::Math
namespace pybind11::detail {
/**
* @brief Converts every Karana quantity value between C++ and Pint.
*
* @tparam Value The scalar, vector, or matrix magnitude type.
* @tparam Tag The quantity metadata tag selecting the Pint dimension and units.
*/
template <typename Value, typename Tag> struct type_caster<Karana::Math::Quantity<Value, Tag>> {
private:
/// Concrete quantity type handled by this caster specialization.
using type = Karana::Math::Quantity<Value, Tag>;
/// Underlying pybind11 caster for the quantity magnitude.
using value_caster = make_caster<Value>;
/// Python typing metadata for the quantity magnitude.
using value_typing = Karana::Math::QuantityValueTyping<Value>;
/// Python annotation for the magnitude type.
static constexpr auto valueTypeName = const_name<value_typing::hasPythonTypeName>(
const_name(value_typing::pythonTypeName), value_caster::name);
/// Python quantity annotation parameterized by the magnitude annotation.
static constexpr auto quantityTypeName =
const_name(Tag::pythonTypeName) + const_name("[") + valueTypeName + const_name("]");
/// Input and output annotation used for generated Python signatures.
static constexpr auto casterName = const_name<value_typing::hasKtypingName>(
io_name(value_typing::pythonTypeName, "") + io_name(" | ", "") + quantityTypeName,
const_name<std::is_arithmetic_v<Value>>(
io_name("typing.SupportsFloat | typing.SupportsIndex | ", ""),
io_name("numpy.typing.ArrayLike | ", "")) +
quantityTypeName);
public:
/// Type caster for pint quantities and associated C++ values
PYBIND11_TYPE_CASTER(type, casterName);
/**
* @brief Converts a Pint quantity or bare Python magnitude to C++.
* @param src The source Python object.
* @param convert Whether implicit conversions are allowed.
* @return True when the source has the expected dimension and value shape.
*/
bool load(handle src, bool convert) {
if (!src) {
return false;
}
object magnitude = reinterpret_borrow<object>(src);
const object pintQuantity = module_::import("pint").attr("Quantity");
if (isinstance(magnitude, pintQuantity)) {
const object kquantities = module_::import("Karana.Math.Kquantities");
const object expectedQuantity = kquantities.attr(Tag::quantityName);
if (!pybind11::cast<bool>(magnitude.attr("check")(expectedQuantity))) {
return false;
}
// Rebuild with Karana's registry before converting to avoid Pint
// registry mismatches for quantities created by another registry.
magnitude = kquantities.attr("ureg")
.attr("Quantity")
.attr("from_tuple")(magnitude.attr("to_tuple")())
.attr("to_base_units")()
.attr("m");
}
value_caster magnitudeCaster;
if (!magnitudeCaster.load(magnitude, convert)) {
return false;
}
value.value = cast_op<Value &&>(std::move(magnitudeCaster));
return true;
}
/**
* @brief Converts a C++ quantity to a Pint quantity in default units.
* @param src The source C++ quantity.
* @param policy The pybind11 return-value policy for the magnitude.
* @param parent The parent Python object, when applicable.
* @return A new reference to the resulting Pint quantity.
*/
static handle cast(const type &src, return_value_policy policy, handle parent) {
const object kquantities = module_::import("Karana.Math.Kquantities");
object magnitude =
reinterpret_steal<object>(value_caster::cast(src.value, policy, parent));
object result = magnitude * kquantities.attr("getDefaultUnits")(
kquantities.attr(Tag::quantityName));
return result.release();
}
};
} // namespace pybind11::detail