Refactor mj_crb and mj_tendonArmature to use CSR M.

PiperOrigin-RevId: 774077388
Change-Id: Id57118a5d66c074766f5c69fd3b889ebc625cbf7
This commit is contained in:
Yuval Tassa
2025-06-21 04:48:07 -07:00
committed by Copybara-Service
parent 14dc7c2a60
commit 2707eadc00
3 changed files with 45 additions and 35 deletions
+41 -35
View File
@@ -1469,9 +1469,12 @@ void mj_transmission(const mjModel* m, mjData* d) {
//-------------------------- inertia ---------------------------------------------------------------
// add tendon armature to qM
// add tendon armature to M
void mj_tendonArmature(const mjModel* m, mjData* d) {
int nv = m->nv, ntendon = m->ntendon, issparse = mj_isSparse(m);
const int* M_rownnz = d->M_rownnz;
const int* M_rowadr = d->M_rowadr;
const int* M_colind = d->M_colind;
for (int k=0; k < ntendon; k++) {
mjtNum armature = m->tendon_armature[k];
@@ -1482,11 +1485,19 @@ void mj_tendonArmature(const mjModel* m, mjData* d) {
// dense
if (!issparse) {
// M += armature * ten_J' * ten_J
mjtNum* ten_J = d->ten_J + nv*k;
for (int i=0; i < m->nv; i++) {
int Madr = m->dof_Madr[i];
for (int j = i; j >= 0; j = m->dof_parentid[j]) {
d->qM[Madr++] += armature * ten_J[j] * ten_J[i];
for (int i=0; i < nv; i++) {
mjtNum ten_J_i = ten_J[i];
if (!ten_J_i) {
continue;
}
// M[i,:] += armature * ten_J[i] * ten_J
int start = M_rowadr[i];
int end = start + M_rownnz[i];
for (int adr = start; adr < end; adr++) {
d->M[adr] += armature * ten_J_i * ten_J[M_colind[adr]];
}
}
}
@@ -1494,29 +1505,24 @@ void mj_tendonArmature(const mjModel* m, mjData* d) {
// sparse
else {
// get sparse info for tendon k
int rowadr = d->ten_J_rowadr[k];
int rownnz = d->ten_J_rownnz[k];
const int* colind = d->ten_J_colind + rowadr;
mjtNum* ten_J = d->ten_J + rowadr;
int J_rowadr = d->ten_J_rowadr[k];
int J_rownnz = d->ten_J_rownnz[k];
const int* J_colind = d->ten_J_colind + J_rowadr;
mjtNum* ten_J = d->ten_J + J_rowadr;
// iterate forward on nonzero rows i
for (int adr_i=0; adr_i < rownnz; adr_i++) {
int i = colind[adr_i];
int Madr = m->dof_Madr[i];
int adr_j = rownnz - 1;
// iterate backward on ancestors of i, find matching column j
for (int j = i; j >= 0; j = m->dof_parentid[j]) {
// reduce adr_j until column index is no bigger than j
while (colind[adr_j] > j && adr_j >= 0) {
adr_j--;
}
// found match, update qM
if (colind[adr_j] == j) {
d->qM[Madr++] += armature * ten_J[adr_j] * ten_J[adr_i];
}
// M += armature * ten_J' * ten_J
for (int j=0; j < J_rownnz; j++) {
mjtNum ten_J_i = ten_J[j];
if (!ten_J_i) {
continue;
}
// M[i,:] += armature * ten_J[i] * ten_J
int i = J_colind[j];
int M_adr = M_rowadr[i];
mju_addToSclSparseInc(d->M + M_adr, ten_J,
M_rownnz[i], M_colind + M_adr,
J_rownnz, J_colind, armature * ten_J_i);
}
}
}
@@ -1526,22 +1532,22 @@ void mj_tendonArmature(const mjModel* m, mjData* d) {
// composite rigid body inertia algorithm
void mj_crb(const mjModel* m, mjData* d) {
int nv = m->nv;
mjtNum buf[6];
mjtNum* crb = d->crb;
int last_body = m->nbody - 1, nv = m->nv;
// crb = cinert
mju_copy(crb, d->cinert, 10*m->nbody);
// backward pass over bodies, accumulate composite inertias
for (int i=last_body; i > 0; i--) {
for (int i=m->nbody - 1; i > 0; i--) {
if (m->body_parentid[i] > 0) {
mju_addTo(crb+10*m->body_parentid[i], crb+10*i, 10);
}
}
// clear qM
mju_zero(d->qM, m->nM);
// clear M
mju_zero(d->M, m->nC);
// dense forward pass over dofs
for (int i=0; i < nv; i++) {
@@ -1549,7 +1555,7 @@ void mj_crb(const mjModel* m, mjData* d) {
if (m->dof_simplenum[i]) {
int n = i + m->dof_simplenum[i];
for (; i < n; i++) {
d->qM[m->dof_Madr[i]] = m->dof_M0[i];
d->M[d->M_rowadr[i]] = m->dof_M0[i];
}
// finish or else fall through with next row
@@ -1559,8 +1565,8 @@ void mj_crb(const mjModel* m, mjData* d) {
}
// init M(i,i) with armature inertia
int Madr_ij = m->dof_Madr[i];
d->qM[Madr_ij] = m->dof_armature[i];
int Madr_ij = d->M_rowadr[i] + d->M_rownnz[i] - 1;
d->M[Madr_ij] = m->dof_armature[i];
// precompute buf = crb_body_i * cdof_i
mju_mulInertVec(buf, crb+10*m->dof_bodyid[i], d->cdof+6*i);
@@ -1568,7 +1574,7 @@ void mj_crb(const mjModel* m, mjData* d) {
// sparse backward pass over ancestors
for (int j=i; j >= 0; j = m->dof_parentid[j]) {
// M(i,j) += cdof_j * (crb_body_i * cdof_i)
d->qM[Madr_ij++] += mju_dot(d->cdof+6*j, buf, 6);
d->M[Madr_ij--] += mju_dot(d->cdof+6*j, buf, 6);
}
}
}
@@ -1579,7 +1585,7 @@ void mj_makeM(const mjModel* m, mjData* d) {
TM_START;
mj_crb(m, d);
mj_tendonArmature(m, d);
mju_gather(d->M, d->qM, d->mapM2M, m->nC);
mju_scatter(d->qM, d->M, d->mapM2M, m->nC);
TM_END(mjTIMER_POS_INERTIA);
}
+3
View File
@@ -1990,6 +1990,9 @@ static void _resetData(const mjModel* m, mjData* d, unsigned char debug_value) {
mju_zero(d->mocap_pos, 3*m->nmocap);
mju_zero(d->mocap_quat, 4*m->nmocap);
// zero out qM, special case because scattring from M skips simple body off-diagonals
mju_zero(d->qM, m->nM);
// copy qpos0 from model
if (m->qpos0) {
memcpy(d->qpos, m->qpos0, m->nq*sizeof(mjtNum));
+1
View File
@@ -237,6 +237,7 @@ TEST_F(CoreSmoothTest, TendonArmature) {
// put only CRB inertia in M2
mj_crb(m, d);
mju_scatter(d->qM, d->M, d->mapM2M, m->nC);
vector<mjtNum> M2(nv*nv);
mj_fullM(m, M2.data(), d->qM);