Implement multi-cell finite element method for interpolated flexes.

This change introduces a `flex_cellcount` field to `mjModel` to specify the number of cells in each dimension for interpolated flexes. The stiffness computation, passive force calculation, and Jacobian derivatives are updated to operate on a per-cell basis, significantly improving performance by localizing computations to the nodes within each cell.

PiperOrigin-RevId: 901216393
Change-Id: Ic23132e609de11e71bb7fef8d1f139daad2ec264
This commit is contained in:
Alessio Quaglino
2026-04-17 04:10:54 -07:00
committed by Copybara-Service
parent 8415dff307
commit 6c7ed66781
36 changed files with 1777 additions and 1039 deletions
+30 -8
View File
@@ -2190,8 +2190,13 @@ void mjCModel::SetSizes() {
nflexshelldata += (int)flexes_[i]->shell.size();
nflexevpair += (int)flexes_[i]->evpair.size()/2;
nflextexcoord += (flexes_[i]->HasTexcoord() ? flexes_[i]->get_texcoord().size()/2 : 0);
if (flexes_[i]->order_ != 0) {
extra_stiffness_size += (3 * flexes_[i]->nnode) * (3 * flexes_[i]->nnode);
if (flexes_[i]->spec.order != 0) {
int npc = (int)pow(flexes_[i]->spec.order + 1, 3);
int ndof_cell = 3 * npc;
int ncells = flexes_[i]->spec.cellcount[0] *
flexes_[i]->spec.cellcount[1] *
flexes_[i]->spec.cellcount[2];
extra_stiffness_size += ncells * ndof_cell * ndof_cell;
}
if (flexes_[i]->interpolated || flexes_[i]->rigid) {
continue;
@@ -3467,18 +3472,30 @@ void mjCModel::CopyObjects(mjModel* m) {
mjuu_copyvec(m->flex_rgba + 4 * i, pfl->rgba, 4);
// elasticity
if (pfl->order_ == 0) {
if (pfl->spec.order == 0) {
m->flex_stiffnessadr[i] = 21 * elem_adr;
} else {
m->flex_stiffnessadr[i] = current_extra_stiffness_adr;
current_extra_stiffness_adr += (3 * pfl->nnode) * (3 * pfl->nnode);
int npc = (int)pow(pfl->spec.order + 1, 3);
int ndof_cell = 3 * npc;
int ncells = pfl->spec.cellcount[0] * pfl->spec.cellcount[1] * pfl->spec.cellcount[2];
current_extra_stiffness_adr += ncells * ndof_cell * ndof_cell;
}
if (!pfl->stiffness.empty()) {
mjuu_copyvec(m->flex_stiffness + m->flex_stiffnessadr[i], pfl->stiffness.data(), pfl->stiffness.size());
mjuu_copyvec(m->flex_stiffness + m->flex_stiffnessadr[i],
pfl->stiffness.data(), pfl->stiffness.size());
} else {
int size = (pfl->order_ == 0) ? 21 * pfl->nelem : (3 * pfl->nnode) * (3 * pfl->nnode);
mjuu_zerovec(m->flex_stiffness + m->flex_stiffnessadr[i], size);
int stiff_size;
if (pfl->spec.order == 0) {
stiff_size = 21 * pfl->nelem;
} else {
int npc = (int)pow(pfl->spec.order + 1, 3);
int ndof_cell = 3 * npc;
int ncells = pfl->spec.cellcount[0] * pfl->spec.cellcount[1] * pfl->spec.cellcount[2];
stiff_size = ncells * ndof_cell * ndof_cell;
}
mjuu_zerovec(m->flex_stiffness + m->flex_stiffnessadr[i], stiff_size);
}
if (!pfl->bending.empty()) {
mjuu_copyvec(m->flex_bending + 17 * edge_adr, pfl->bending.data(), pfl->bending.size());
@@ -3613,7 +3630,12 @@ void mjCModel::CopyObjects(mjModel* m) {
}
// set interpolation type, only two types for now
m->flex_interp[i] = pfl->order_;
m->flex_interp[i] = pfl->spec.order;
// set cell count for multi-cell finite cell method
m->flex_cellnum[3*i+0] = pfl->spec.cellcount[0];
m->flex_cellnum[3*i+1] = pfl->spec.cellcount[1];
m->flex_cellnum[3*i+2] = pfl->spec.cellcount[2];
// convert edge pairs to int array, set edge rigid
for (int k=0; k < pfl->nedge; k++) {