Naming and indexing conventions#
Genesis World uses a small, consistent set of naming rules across its API and its source. This page is the reference for three of them: how an entity is identified (name, uid, idx), how indices switch between an entity’s own numbering and the solver’s global numbering (*_idx_local vs *_idx), and the i_* loop-variable and field-naming conventions you will meet when reading solver code.
Two conventions in one sentence: identifiers answer “which entity is this,” and indices answer “which slot in a state array.” They are unrelated numbering systems, and mixing them is the most common source of off-by-entity bugs.
Identifying an entity: name, uid, and idx#
Every entity carries three identifiers, each for a different job:
name: a human-readable string. You pass it toscene.add_entity(..., name=...), or Genesis World generates one from the morph type and a UID prefix. Names are how you look an entity up later.uid: a globally unique ID assigned at creation. It never collides across entities and is stable for the life of the object. Itsshort()form (a 7-character prefix) is what appears in terminal logs.idx: the entity’s integer position in the scene’s creation order. This is an index, not an identifier you should hand-write. It exists so the engine can address the entity’s data.
The naming tutorial examples/tutorials/entity_name.py shows all three in use. Look up an entity by name or by short UID:
box = scene.add_entity(gs.morphs.Box(pos=(0, 0, 0.5), size=(0.2, 0.2, 0.2)))
ground = scene.add_entity(gs.morphs.Plane(), name="ground")
scene.get_entity(name="ground") # exact-name lookup
scene.get_entity(uid=box.uid.short()) # short-UID lookup (substring of the full uid)
scene.entity_names # tuple of every entity's name, in creation order
Prefer name for lookups you write by hand, and reserve uid for disambiguating entities that share a generated name. The same name / uid pair identifies links and joints within a rigid entity. entity.get_link(name=...) and entity.get_joint(name=...) work the same way.
Identifier |
Type |
Assigned by |
Use it to |
|---|---|---|---|
|
|
you, or auto-generated |
look an entity up in a scene |
|
UID object |
Genesis World, at creation |
disambiguate; read from logs via |
|
|
Genesis World, at creation |
address the entity’s data (rarely written by hand) |
Local and global indices#
A rigid solver stores the state of every entity in flat, shared arrays: one row per dof (degree of freedom), one per link, one per configuration variable q, and so on. So there are two ways to number the same dof:
Global index (
*_idx): the dof’s absolute row in the solver’s arrays, counting across all entities. A two-armed scene numbers the second arm’s dofs after the first arm’s.Local index (
*_idx_local): the dof’s position within its own entity, always starting at zero. The first dof of any entity is local index0, regardless of what was added before it.
The two differ by a per-entity offset. For dofs it is entity.dof_start; the entity also exposes link_start and q_start for the link and q arrays. A joint’s dofs_idx (global) and dofs_idx_local (local) properties are defined by exactly this shift:
# genesis/engine/entities/rigid_entity/rigid_joint.py
dofs_idx = list(range(dof_start, dof_end))
dofs_idx_local = list(range(dof_start - entity.dof_start, dof_end - entity.dof_start))
Because local indices are stable no matter how many other entities share the scene, they are what you build control targets from. The control tutorial examples/tutorials/control_your_robot.py reads a Franka’s motor dofs by joint name, then addresses them locally:
motors_dof_idx = [franka.get_joint(name).dofs_idx_local[0] for name in joints_name]
franka.set_dofs_kp(
kp=np.array([4500, 4500, 3500, 3500, 2000, 2000, 2000, 100, 100]),
dofs_idx_local=motors_dof_idx,
)
How indices appear in the API#
Entity methods that read or write batched state take a local selector and translate it to global indices internally, through RigidEntity._get_global_idx, before calling the solver. The argument is named *_idx_local to make the numbering explicit at the call site:
franka.set_dofs_position(position, dofs_idx_local=motors_dof_idx)
franka.get_links_pos(links_idx_local=[0, 1])
franka.set_qpos(qpos, qs_idx_local=...)
Entity methods take local indices.
dofs_idx_local,links_idx_local,qs_idx_local. PassingNoneselects the entity’s full range.Solver methods take global indices. The
RigidSolverequivalents accept already-resolveddofs_idx,links_idx, and so on. Reach for them only when you are working across entities at the solver level.envs_idxhas no local form. Environment (env) selection is scene-wide, so batched methods take a singleenvs_idxthat indexes environments directly. See parallel simulation for how the batch dimension works.
Note
The properties named without a suffix (a joint’s dof_start, a link’s idx, an entity’s idx) are global. The _local suffix is only ever added to opt into entity-relative numbering. When in doubt, an index is global.
Field and loop-variable naming in the source#
The conventions above surface names you also see when reading solver code. If you only use the public API, you can stop here; the rest is a map for the source under genesis/engine/solvers/.
Data fields follow <representation>_<computation-type>. The representation is always plural (dofs, links, particles, elements), and the computation-type suffix marks how the field is used:
*_state: dynamic state updated every solver step (for exampledofs_state,links_state).*_info: static properties fixed for the simulation, such as mass or stiffness (dofs_info,geom_info).*_render: fields consumed only by visualization, never by physics (particles_render).*_ng: a state variant withrequires_graddisabled (particles_state_ng);*_reorderedmarks a spatially reordered cache.
Loop indices are i_<representation-initial>. Kernels iterate flat arrays with short names whose letter names the thing being indexed. These are the global indices described above, not local ones:
Variable |
Indexes |
|---|---|
|
batch: the environment |
|
entity |
|
link |
|
joint |
|
dof |
|
geometry ( |
|
vertex |
For the concrete field layouts of each solver (the full state and info structs), read the solver files themselves, starting from rigid_solver.py and the entity classes under genesis/engine/entities/.
See also#
Hello, Genesis World: where
nameand entities are first introduced.Control your robot: local dof indices in a full control loop.
RigidJoint API and RigidEntity API: the
dofs_idx/dofs_idx_localproperties and the*_idx_localmethods.