(conventions_page)=

# Conventions



## Terminology


###  Python Namespaces & Conventions

kdFlex exposes its functionality through a small set of well‑structured
Python packages (namespaces).  The design follows a “layered” approach:
low‑level C++ core wrapped by pybind11, higher‑level Python helpers, and
finally the user‑facing API.  Below is a concise map of the main
namespaces and the conventions you’ll encounter when writing or reading
kdFlex code.

All top‑level modules are prefixed with `Karana.` – this is the “kdFlex” root. 

**Naming Style**  
   * **Classes** – `PascalCase` (e.g., `Multibody`, `PhysicalBody`).  
   * **Functions / helpers** – `snake_case` (e.g., `discard()`, `allReady()`).  
   * **Constants / enums** – `UPPER_SNAKE_CASE` (e.g., `IntegratorType.EULER`, `MMSolverType.SINGLE`).



| Namespace | Purpose | Typical imports | Key classes / functions |
|-----------|---------|-----------------|-------------------------|
| **`Karana.Core (kc)`** | Core utilities that are shared across all layers (memory, containers, helpers). | `import  Karana.Core as kd` |  `discard, allReady, BaseContainer` |
| **`Karana.Frame (kf)`** | Handles the *frame* hierarchy – the kinematic tree of coordinate frames. | `import Karana.Frame as kf` | `FrameContainer, Frame` | 
| **`Karana.Math (km)`** | Mathematical primitives (vectors, matrices, quaternions, integrators). | `import  Karana.Math as km` | `SpatialInertia, UnitQuaternion, HomTran` | 
| **`Karana.Dynamics (kd)`** | Multibody dynamics engine (bodies, hinges, constraints, kinematics, dynamics). | `import Karana.Dynamics as kd` | `Multibody, PhysicalBody, HingeType, StatePropagator, TimedEvent` |
| **`Karana.Scene (ks)`** | Geometry and visualization  | `impost Karana.Scene as ks` | `Scene, ProxyScene, WebScene` |

Consistent use of Python import shorthand as shown below can help
improve the readability of Python scripts.

```python

import Karana.Core as kc 
import Karana.Frame as kf
import Karana.Math as km
import Karana.Dynamics as kd
import Karana.Scene as ks
import Karana.Var as kv

import Karana.WebUI as kw
import Karana.Dynamics.SOADyn_types as kdt
import Karana.Scene.Scene_types as kst
import Karana.Models as kmdl
import Karana.Collision as kcol
```

Using such imports, the `Multibody` class could be referenced via
`kd.Multibody` instead of `Karana.Dynamics.Multibody` in Python code.


While most Python classes are thin wrappers around underlying C++ classes. An
important exception are the `Eigen` based `Karana::Math::Vec` and
`Karana::Math::Mat` C++ matrix/vector classes. These C++ classes instead map into
and use `numpy arrays` at the Python level.

By keeping these namespaces and conventions in mind, you’ll be able to
navigate kdFlex’s API, write clean simulation scripts, and extend the
framework with confidence.


### C++ namespaces and conventions


kdFlex is a C++ library that exposes its functionality through a small
set of well‑defined namespaces.  The design follows a “core‑first”
approach: the C++ implementation is wrapped by pybind11 for Python, but
the C++ API is the source of truth.  Below is a concise map of the main
C++ namespaces and the conventions you’ll encounter when reading or
extending the source.

All top‑level modules are prefixed with `Karana::`.

| Namespace | Purpose | Typical classes / functions |
|-----------|---------|-----------------------------|
| **`Karana::Core (kc)`** | Low‑level utilities shared by all modules (memory, containers, helpers). | `BaseContainer`, `Allocator`, `ks_ptr`, `discard()`, `allReady()` |
| **`Karana::Frame (kf)`** | Frame hierarchy – the kinematic tree of coordinate frames. | `FrameContainer`, `Frame`, `HomTran` |
| **`Karana::Math (km)`** | Mathematical primitives (vectors, matrices, quaternions, integrators). | `Vec`, `Vec3`, `Mat`, `Mat33`, `UnitQuaternion`, `SpatialInertia`, `IntegratorType` | 
| **`Karana::Dynamics (kd)`** | Multibody dynamics engine (SOA, ATBI/ABI, constraints). | `Multibody`, `PhysicalBody`, `HingeType`, `StatePropagator`, `TimedEvent`, `MMSolverType` | *`Multibody` is the main entry point; use `StatePropagator` for integration.* |
| **`Karana::Scene (ks)`** | Geometries and visualization | `ProxyScene`, `ScenePart`, `Color` | 


Abbreviations such as below are used for more succinct ways to use the
namespaces within C++ code.

```cpp

namespace kc = Karana::Core;
namespace kf = Karana::Frame;
namespace km = Karana::Math;
namespace kd = Karana::Dynamics;
namespace ks = Karana::Scene;

namespace kmdl = Karana::Models;
namespace kcoll = Karana::Collision;

```

These namespaces and conventions form the backbone of kdFlex’s C++
code base and are the key to navigating, understanding, and extending the
library.


### Object identifiers

Most kdflex classes are derived from the `Karana::Core::Base` C++ class, and
as such every object has

- a name (not necessarily unique), accessed via the `name()` method
- a unique numeric id, accessed via the `id()` method
- a `typeString()` method that returns a string name for its class


### Multibody root body

Each `Multibody` instance has a unique name with a virtual root body
named as `_MBVROOT_<mbname>`. The `isRootBody()` method returns `true`
for only the multibody root physical body, and `false` for other
physical body instances.


### Coordinates

Coordinate values define the state of the multibody system. The
following naming conventions are used at all levels (eg. subhinge,
hinge, body deformation, subtree etc) for the coordinate variables:

- `Q` is used for configuration coordinates
- `Qdot` is used for the time derivatives for `Q`.
- `U` is used for velocity coordinates. Often `U` is the same as `Qdot`, and that is not always the case. In some cases, such as spherical subhinges,  `U` is made of  quasi-velocity coordinates
- `Udot` is used for the time derivatives of `U`
- `T` is used for generalized forces

The `nQ()` method is used to query the size of the `Q` coordinates, and
the `nU()` method for the size of the `U` coordinates. In most cases,
the size of the `Q` and `U` coordinates are the same. However this is
not a requirement, and an exception to this is the
`SphericalQuatSubhinge` class where there the number of `Q` coordinates
is larger than the number of `U` coordinates. The sizes of `U` and `T`
are always equal.



### Passive Rotation Convention

In kdFlex a rotation matrix (or quaternion) is a *passive* transform
that takes a vector from a body‑fixed frame and expresses it in the
world (or parent) frame.  All internal calculations, Jacobians, and
dynamics equations are built around this convention, so users should
always interpret rotation data as “world‑to‑body” transforms. Thus a
vector transforms as ${}^a v = {}^aR_b\ {}^b v$, i.e., it is rotated
from the “b” frame into the “a” frame.

All kdFlex modules adhere to this convention, so you can freely mix and
match objects without worrying about hidden frame flips.


### UnitQuaternion versus RotationVector attitude representations

kdFlex relies almost completely on the `UnitQuaternion` class for
attitude related computations. Unit quaternions avoid the need for
trigonometric values and are computationally efficient. The one drawback
of unit quaternions is that the unit quaternion is a 4-parameter
parameter representation of attitude. While the redundant coordinate
helps avoid singularities in this attitude representation, it does
require the enforcement of the unit norm constraint on the attitude
representation. 

The `SphericalSubhinge` allows arbitrary relative orientation across the
subhinge, and requires choosing `Q` generalized coordinates to
parameterize such relative orientation.  Using unit quaternions for `Q`
coordinates for this subhinge type would lead to non-minimal, redundant
coordinate representation. Non-minimal coordinates require differential
algebraic solvers (DAE) for numerical integration, as well as requiring
more complex dynamics solution methods to handle the redundant
coordinate constraints.

To avoid the introduction of this unit norm constraint into dynamics
computations, the `SphericalSubhinge` class uses the minimal 3-vector
`RotationVector` representation for its `Q` coordinates for the relative
attitude across the subhinge. This is the one exception to use of unit
quaternions elsewhere. The use of minimal 3-vector representation for
attitude does introduce singularities in the attitude representation.
Local charts are used t to handle these singularities.





### Ktime for time representation

**kdFlex – Ktime: the canonical time type**

kdFlex represents all simulation times with a single, high‑precision type called `Ktime`.  The design of `Ktime` is driven by the need for *unambiguous, nanosecond‑accurate* timestamps that can be used both in the C++ core and in the Python bindings.


####  What is `Ktime`?

| Layer | Definition | Precision | Why it matters |
|-------|------------|-----------|----------------|
| **C++** | `using Ktime = std::chrono::nanoseconds;` (in `Karana::Math::Defs.h`) | 1 ns | Guarantees that every time value is an integer number of nanoseconds, eliminating floating‑point rounding errors. |
| **Python** | `numpy.timedelta64` (via a pybind11 wrapper) | 1 ns | Mirrors the C++ type; `numpy.timedelta64` can represent nanoseconds exactly and integrates cleanly with NumPy arrays. |

The choice of nanoseconds is deliberate: it is the smallest unit that still fits comfortably in a 64‑bit integer (about 292 years of simulation time) and is large enough to avoid overflow in most practical simulations.


kdFlex ships with a small helper `Ktime secondsToKtime(double seconds)` to go from a floating‑point second value to `Ktime`. In Python the conversion is handled automatically by the pybind11 wrapper, so a user can simply pass a `float` or a `numpy.timedelta64` and the binding will take care of the conversion.

####  Why a dedicated time type?

1. **Determinism** – All time arithmetic is integer‑based, so two runs with identical inputs will produce identical timestamps, even on different hardware or operating systems.
2. **Precision** – Nanosecond resolution is more than enough for most simulations (e.g., 1 ms or 10 ms integrator steps) while still allowing very long simulation horizons.
3. **Interoperability** – The same type is exposed to Python, so there is no hidden conversion between C++ and Python that could introduce drift.
4. **Performance** – `std::chrono::nanoseconds` is a lightweight wrapper around `int64_t`; arithmetic is as fast as plain integer math.




### Spatial Vectors


kdFlex uses *spatial notation* throughout its kinematics and dynamics
code.  A `SpatialVector` is the canonical container for any
6‑dimensional quantity that has an *angular* part `w` (usually a torque or
angular velocity) and a *linear* part `v` (usually a force or linear
velocity).  The class is defined in `Karana/Math/SpatialVector.h` and is
exposed to both C++ and Python. The class itself is lightweight – it simply holds two `Vec3` members. However, on conversion to a 6-vector,  the `w` (angular) values are stored in the first three components, and  the `v` (linear) in  the last three components.
* 

####   Why spatial notation?

* **Compactness** – A 6‑D vector replaces two 3‑D vectors and a cross‑product operation.  
* **Consistency** – The same data structure is used for velocities, forces, and Jacobian rows, making the code easier to read and maintain.  
* **Transformations** - rigid-body transformations are more concise and simpler simpler with spatial vector notation.
* **Mathematical elegance** – The Newton‑Euler equations and the recursive Newton‑Euler algorithm are naturally expressed in spatial form.

---

The `SpatialVector` class is a lightweight, 6‑dimensional container that
holds an angular part (`w`) and a linear part (`v`).  It is used
everywhere in kdFlex where a quantity naturally has both angular and
linear components—spatial velocities, forces, Jacobian rows, and
constraint forces.  By treating these quantities as a single object, the
its kinematics and dynamics quantities are concise, mathematically
clean, and efficient.


<!--

### Rotational inertia cross-terms

The convention in 

### relSpVel, relSpAccel - oframe relative/observed/representation




### onode/pnode meaning

### oframe/pframe meaning

### AB vs TA vs CE forward dynamics

### TA vs FA vs CE model

!-->


## Concepts


### Integrator owns the state



In the context of time domain simulation using the `StatePropagator`,
the system continuous state consists of the  subgraph's `Q` and
`U` coordinates, together with any continuous states that the `KModel`
instances may have.  In this scenario, the *integrator* is responsible
for storing and updating the system state over time. As such, the
integrator is the component that *owns* the system state. 

An important implications of this is that initializing or changing the
`Q` and `U` values in the subgraph by itself has no effect on the system
state. The state value has to be transferred to the integrator for the
new state values  to have an effect. The usual steps to do this are:

- set the new state values in the subgraph's coordinates and KModel instances
- call `x = StatePropagator::assembleState()` to gather up these values into a vector for the integrator
- call `StatePropagator::setState(x)` to transfer the state to the integrator.

A common mistake is for users to just do the first step above, and see
the changes have no effect! The latter steps are required.

<!--

### using TA as basic model - tree + cutjuts
### avoid Python if looking to optimize speed, but use it for convenience
### hinges vs constraints - similar
### 
### use eigen at C++ for matrix/vector, numpy at Python level
### newtonian frame vs fc root and dynamics frame
### dump methods all all levels
### always use units, quantities
### internal units - SI
### Python API mirroring C++ API
### frames layer - the ties that bind. regular frames, bodies, nodes, Spice

### Importing/exporting data

using DataStruct

file naming 'kd.yaml' etc
!-->


## Software

###  Object life-cycle

kdFlex follows a strict *factory‑plus‑explicit‑destruction* pattern.  
All objects are created through a static `create()` method and destroyed
by calling the instance’s `discard()` method.  This convention is
documented in the usage guide and is enforced by the C++ core as well as
the Python bindings.  What you should remember:

1. **Never use `new` or `delete` directly** – always use `create()` and `discard()`.  
2. **Do not keep raw pointers** – keep the `kc::ks_ptr<T>` (or the Python object) as long as you need the object.  
3. **Call `discard()` when you’re done** – this frees resources immediately and avoids dangling references.  
4. **Python users** – you can rely on automatic cleanup, but calling `discard()` explicitly is good practice, especially in long‑running simulations.


The one exception to this using is the `Node` class which has the
`lookupOrCreate()` method in place of the `create()` method. For nodes,
`lookupOrCreate()` is simply a higher‑level facade that leverages
kdFlex’s core creation/destruction convention while adding name‑based
lookup semantics from the pool of detached Node objects. The
`Node::detach()` method can be used to release a node from a body and
add it to the pool. The `discard()` can be used to permanently delete a
node.


kdFlex’s object life-cycle is governed by the `create()` factory method
and the `discard()` destructor method.  This pattern guarantees safe
memory management, consistent API usage, and seamless integration
between C++ and Python.


### Object health


In kdflex, objects constructors generally perform only essential work
and leave objects in a unhealthy state during the over overall model
construction process. `ensureHealthy()` is a *runtime‑sanity* helper
that is available for objects to verify that all objects they depend on
are healthy, and to finish up any remaining setup steps needed to get
them into configuration suitable for use by the simulation engine. Thus
for instance the `FrameContainer::ensureHealthy()` method verifies that
there are no unattached frames in the system, and updates internal
caches needed at run-time.

Many methods can only be called on healthy objects, and use the
`isHealthy()` method to check the object state.  The `ensureHealthy()`
method is usually called implicitly by higher‑level classes
(`Multibody`, `Scene`, `StatePropagator`) but can be called explicitly
by the user when they want to validate an object after a batch of
changes.  It is thus only necessary to call `ensureHealthy()` on the
highest level object, such as the `Multibody` or `StatePropagator`
instance the end of the model definition to get all the objects ready
for computations. Calling it on a healthy object only involves checking
the health flag and is inexpensive and be safely called multiple times.

Run-time configuration changes, such as from adding or reattaching
bodies, will automatically mark objects such as the `Multibody` instance
as unhealthy, and will thus require calls to `ensureHealthy()` before
continuing with the simulation.

A healthy state only ensures the structural integrity of an object, and
by itself does not imply that required numerical parameters (eg. mass
properties) etc have been initialized. An object is truly ready for
computational use only after such parameters have been set, and the
`isReady()` method can be used to verify that this has been done. Bottom
line, the `isHealthy()` and `isReady()` methods should both return true
for an object to be ready for computations.


### Object numerical readiness

Uninitialized parameters and state values are some of the most difficult
errors to track down. Downstream errors can be difficult to track down
to the root cause from such uninitialized values. To address this,
kdflex sets all parameter and state values to known uninitialized
values. The `isReady()` method is available for all objects derived from
`Base`. This method returns false if any of the numerical parameters and
states for the object are detected as remaining uninitialized. In
addition, the `Base::allReady()` method is available to verify that all
objects parameters have been initialized, i.e. the objects are ready for
numerical computation. This method will generate messages for any
objects that are detected as uninitialized. It is highly recommended
that `allReady()` be called before initiating simulation computations. 

In summary, it is recommended that the simulation include the following  steps:

- create simulation objects
- call `assert <top level>.ensureHealthy()` on the top level object to
  ensure that all objects are healthy
- initialize all numerical parameters and states in the multibody system
  and the `KModel` instances
- call `assert Karana.Core.allReady()`to verify that there are no uninitialized parameters remaining in the system
- carry out simulation computations

<!--






### allDestroyed
### usage tracking

allDestroyed call
### add atExit to clean up



### Add environment scene part specs to vroot, and not just add to
    frame. this will ensure that they can be loaded back from DS files.
### orientation convention - aerospace vs robotics

### using smart pointers

   * kdFlex uses `ks_ptr` (C++ smart pointers) under the hood.  In Python you normally ignore them; the pybind11 wrappers keep objects alive as long as they’re referenced.  


### some methods take references, some shared pointers

!-->
