diff --git a/doc/XMLreference.rst b/doc/XMLreference.rst index 0e6964fc..ab3a397e 100644 --- a/doc/XMLreference.rst +++ b/doc/XMLreference.rst @@ -3136,12 +3136,7 @@ coordinates results in compiler error. See :ref:`CComposite` in the modeling gui .. _body-composite-vertex: :at:`vertex`: :at-val:`real(3*nvert), optional` - Vertex 3D positions in global coordinates (cable and shell). - -.. _body-composite-face: - -:at:`face`: :at-val:`real(3*nvert), optional` - Face connectivity of the vertices (shell only). + Vertex 3D positions in global coordinates (cable only). .. _body-composite-initial: diff --git a/doc/XMLschema.rst b/doc/XMLschema.rst index 02bccf3f..475431fc 100644 --- a/doc/XMLschema.rst +++ b/doc/XMLschema.rst @@ -402,9 +402,7 @@ | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | | | | | :ref:`offset` | :ref:`flatinertia` | :ref:`solrefsmooth` | :ref:`solimpsmooth` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`vertex` | :ref:`face` | :ref:`initial` | :ref:`curve` | | -| | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | -| | | | :ref:`size` | | | | | +| | | | :ref:`vertex` | :ref:`initial` | :ref:`curve` | :ref:`size` | | | | | +-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+-----------------------------------------------------------------+ | +------------------------------------+----+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | |_2| composite |br| |_2| |L| | | .. table:: | diff --git a/doc/changelog.rst b/doc/changelog.rst index 5d24e8e4..34b2cf16 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -17,7 +17,8 @@ General the MPR algorithm. The semantics of these options remain identical. - The functions ``mjs_findMesh`` and ``mjs_findKeyframe`` were replaced by ``mjs_findElement``, which allows to look for any object type. - + - The experimental use of 2D/3D elasticity plugins with :ref:`composite` has been removed. Users + should instead use :ref:`flexcomp`, which provides the correct collision behavior. - Added the :ref:`nativeccd` flag. When this flag is enabled, general convex collision detection is handled natively, as opposed to using `libccd `__. This feature is in early stages of testing. diff --git a/model/plugin/elasticity/flag.xml b/model/plugin/elasticity/flag.xml deleted file mode 100644 index ad093663..00000000 --- a/model/plugin/elasticity/flag.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/model/plugin/elasticity/floppy.xml b/model/plugin/elasticity/floppy.xml deleted file mode 100644 index 5819451f..00000000 --- a/model/plugin/elasticity/floppy.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - diff --git a/model/plugin/elasticity/jelly.xml b/model/plugin/elasticity/jelly.xml deleted file mode 100644 index 7ee3cb04..00000000 --- a/model/plugin/elasticity/jelly.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - diff --git a/model/plugin/elasticity/plate.xml b/model/plugin/elasticity/plate.xml deleted file mode 100644 index 24691e05..00000000 --- a/model/plugin/elasticity/plate.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - diff --git a/model/plugin/elasticity/poncho.xml b/model/plugin/elasticity/poncho.xml deleted file mode 100644 index 4a05599e..00000000 --- a/model/plugin/elasticity/poncho.xml +++ /dev/null @@ -1,1416 +0,0 @@ - - - - - - diff --git a/model/plugin/elasticity/press.xml b/model/plugin/elasticity/press.xml deleted file mode 100644 index 81a86574..00000000 --- a/model/plugin/elasticity/press.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - diff --git a/plugin/elasticity/membrane.cc b/plugin/elasticity/membrane.cc index f2f88009..c380141d 100644 --- a/plugin/elasticity/membrane.cc +++ b/plugin/elasticity/membrane.cc @@ -123,8 +123,7 @@ Membrane::Membrane(const mjModel* m, mjData* d, int instance, mjtNum nu, } // vertex positions - mjtNum* body_pos = - f0 < 0 ? m->body_pos + 3*i0 : m->flex_xvert0 + 3*m->flex_vertadr[f0]; + mjtNum* body_pos = m->flex_xvert0 + 3*m->flex_vertadr[f0]; // generate triangles from the vertices nt = CreateStencils(elements, edges, simplex, edgeidx); @@ -136,7 +135,7 @@ Membrane::Membrane(const mjModel* m, mjData* d, int instance, mjtNum nu, for (int t = 0; t < nt; t++) { int* v = elements[t].vertices; for (int i = 0; i < kNumVerts; i++) { - int bi = f0 < 0 ? i0+v[i] : m->flex_vertbodyid[m->flex_vertadr[f0]+v[i]]; + int bi = m->flex_vertbodyid[m->flex_vertadr[f0]+v[i]]; if (bi && m->body_plugin[bi] != instance) { mju_error("Body %d does not have plugin instance %d", bi, instance); } @@ -182,12 +181,7 @@ void Membrane::Compute(const mjModel* m, mjData* d, int instance) { mjtNum kD = damping / m->opt.timestep; // update edge lengths - if (f0 < 0) { - UpdateSquaredLengths(deformed, edges, d->xpos+3*i0); - } else { - UpdateSquaredLengthsFlex(deformed, - d->flexedge_length + m->flex_edgeadr[f0]); - } + UpdateSquaredLengthsFlex(deformed, d->flexedge_length + m->flex_edgeadr[f0]); // we add generalized Rayleigh damping as decribed in Section 5.2 of // Kharevych et al., "Geometric, Variational Integrators for Computer @@ -199,18 +193,14 @@ void Membrane::Compute(const mjModel* m, mjData* d, int instance) { } // compute gradient of elastic energy and insert into passive force - int flex_vertadr = f0 < 0 ? -1 : m->flex_vertadr[f0]; - mjtNum* xpos = f0 < 0 ? d->xpos + 3*i0 : d->flexvert_xpos + 3*flex_vertadr; - mjtNum* qfrc = d->qfrc_passive + (f0 < 0 ? m->body_dofadr[i0] : 0); + int flex_vertadr = m->flex_vertadr[f0]; + mjtNum* xpos = d->flexvert_xpos + 3*flex_vertadr; + mjtNum* qfrc = d->qfrc_passive; ComputeForce(force, elements, metric, elongation, m, xpos); // insert into passive force - if (f0 < 0) { - mju_addTo(qfrc, force.data(), force.size()); - } else { - AddFlexForce(qfrc, force, m, d, xpos, f0); - } + AddFlexForce(qfrc, force, m, d, xpos, f0); // update stored lengths if (kD > 0) { diff --git a/plugin/elasticity/solid.cc b/plugin/elasticity/solid.cc index bbb35b88..f624929c 100644 --- a/plugin/elasticity/solid.cc +++ b/plugin/elasticity/solid.cc @@ -131,8 +131,7 @@ Solid::Solid(const mjModel* m, mjData* d, int instance, mjtNum nu, mjtNum E, } // vertex positions - mjtNum* body_pos = - f0 < 0 ? m->body_pos + 3*i0 : m->flex_xvert0 + 3*m->flex_vertadr[f0]; + mjtNum* body_pos = m->flex_xvert0 + 3*m->flex_vertadr[f0]; // generate tetrahedra from the vertices nt = CreateStencils(elements, edges, simplex, edgeidx); @@ -144,7 +143,7 @@ Solid::Solid(const mjModel* m, mjData* d, int instance, mjtNum nu, mjtNum E, for (int t = 0; t < nt; t++) { int* v = elements[t].vertices; for (int i = 0; i < kNumVerts; i++) { - int bi = f0 < 0 ? i0+v[i] : m->flex_vertbodyid[m->flex_vertadr[f0]+v[i]]; + int bi = m->flex_vertbodyid[m->flex_vertadr[f0]+v[i]]; if (bi && m->body_plugin[bi] != instance) { mju_error("Body %d does not have plugin instance %d", bi, instance); } @@ -189,12 +188,7 @@ void Solid::Compute(const mjModel* m, mjData* d, int instance) { mjtNum kD = damping / m->opt.timestep; // update edge lengths - if (f0 < 0) { - UpdateSquaredLengths(deformed, edges, d->xpos+3*i0); - } else { - UpdateSquaredLengthsFlex(deformed, - d->flexedge_length + m->flex_edgeadr[f0]); - } + UpdateSquaredLengthsFlex(deformed, d->flexedge_length + m->flex_edgeadr[f0]); // we add generalized Rayleigh damping as decribed in Section 5.2 of // Kharevych et al., "Geometric, Variational Integrators for Computer @@ -206,18 +200,14 @@ void Solid::Compute(const mjModel* m, mjData* d, int instance) { } // compute gradient of elastic energy and insert into passive force - int flex_vertadr = f0 < 0 ? -1 : m->flex_vertadr[f0]; - mjtNum* xpos = f0 < 0 ? d->xpos + 3*i0 : d->flexvert_xpos + 3*flex_vertadr; - mjtNum* qfrc = d->qfrc_passive + (f0 < 0 ? m->body_dofadr[i0] : 0); + int flex_vertadr = m->flex_vertadr[f0]; + mjtNum* xpos = d->flexvert_xpos + 3*flex_vertadr; + mjtNum* qfrc = d->qfrc_passive; ComputeForce(force, elements, metric, elongation, m, xpos); // insert into passive force - if (f0 < 0) { - mju_addTo(qfrc, force.data(), force.size()); - } else { - AddFlexForce(qfrc, force, m, d, xpos, f0); - } + AddFlexForce(qfrc, force, m, d, xpos, f0); // update stored lengths if (kD > 0) { diff --git a/src/user/user_composite.cc b/src/user/user_composite.cc index f76e2660..26c3a3db 100644 --- a/src/user/user_composite.cc +++ b/src/user/user_composite.cc @@ -301,6 +301,17 @@ bool mjCComposite::Make(mjSpec* spec, mjsBody* body, char* error, int error_sz) } } + // check plugin compatibility + // TODO: move mujoco.elasticity.cable to the engine + if (plugin.active) { + if (type != mjCOMPTYPE_CABLE) { + return comperr(error, "Only cable composite supports plugins", error_sz); + } + if (plugin_name != "mujoco.elasticity.cable") { + return comperr(error, "Only mujoco.elasticity.cable is supported by composites", error_sz); + } + } + // overwrite plugin name if (plugin_instance_name.empty() && plugin.active) { plugin_instance_name = "composite" + prefix; @@ -372,93 +383,6 @@ bool mjCComposite::MakeParticle(mjCModel* model, mjsBody* body, char* error, int } } - // create faces - if (userface.empty()) { - if (dim == 3) { - int cube2tets[6][4] = {{0, 3, 1, 7}, {0, 1, 4, 7}, - {1, 3, 2, 7}, {1, 2, 6, 7}, - {1, 5, 4, 7}, {1, 6, 5, 7}}; - for (int ix = 0; ix < count[0]-1; ix++) { - for (int iy = 0; iy < count[1]-1; iy++) { - for (int iz = 0; iz < count[2]-1; iz++) { - int vert[8] = { - count[2]*count[1]*(ix+0) + count[2]*(iy+0) + iz+0, - count[2]*count[1]*(ix+1) + count[2]*(iy+0) + iz+0, - count[2]*count[1]*(ix+1) + count[2]*(iy+1) + iz+0, - count[2]*count[1]*(ix+0) + count[2]*(iy+1) + iz+0, - count[2]*count[1]*(ix+0) + count[2]*(iy+0) + iz+1, - count[2]*count[1]*(ix+1) + count[2]*(iy+0) + iz+1, - count[2]*count[1]*(ix+1) + count[2]*(iy+1) + iz+1, - count[2]*count[1]*(ix+0) + count[2]*(iy+1) + iz+1, - }; - for (int s = 0; s < 6; s++) { - for (int v = 0; v < 4; v++) { - face.push_back(vert[cube2tets[s][v]]); - } - } - } - } - } - } else if (dim == 2) { - int quad2tri[2][3] = {{0, 1, 2}, {0, 2, 3}}; - for (int ix = 0; ix < count[0]-1; ix++) { - for (int iy = 0; iy < count[1]-1; iy++) { - int vert[4] = { - count[2]*count[1]*(ix+0) + count[2]*(iy+0), - count[2]*count[1]*(ix+1) + count[2]*(iy+0), - count[2]*count[1]*(ix+1) + count[2]*(iy+1), - count[2]*count[1]*(ix+0) + count[2]*(iy+1), - }; - for (int s = 0; s < 2; s++) { - for (int v = 0; v < 3; v++) { - face.push_back(vert[quad2tri[s][v]]); - } - } - } - } - } - userface = VectorToString(face); - } else { - dim = 2; // can only load a surface for now - face = StringToVector(userface); - for (int i=0; i volume(uservert.size()/3); - double thickness = 1; - if (dim == 2 && plugin.active) { - try { - mjCPlugin* pplugin = static_cast(plugin.instance); - thickness = std::stod(pplugin->config_attribs["thickness"], nullptr); - } catch (const std::invalid_argument& e) { - return comperr(error, "Invalid thickness attribute", error_sz); - } - } - if (!userface.empty()) { - face = StringToVector(userface); - for (int j=0; jtype = mjGEOM_SPHERE; mju::sprintf_arr(txt, "%sS%d", prefix.c_str(), i); mjs_setString(s->name, txt); - - // add plugin - if (plugin.active) { - mjsPlugin* pplugin = &b->plugin; - mjCPlugin* cplugin = static_cast(plugin.instance); - pplugin->active = true; - pplugin->instance = plugin.instance; - mjs_setString(pplugin->instance_name, plugin_instance_name.c_str()); - mjs_setString(pplugin->name, mjs_getString(plugin.name)); - - if (i==0 && !cplugin->config_attribs["face"].empty()) { - return comperr(error, "Face attribute already exists in plugin", error_sz); - } - - cplugin->config_attribs["face"] = userface; - cplugin->config_attribs["edge"] = ""; - - // update density - if (dim == 2) { - g->density *= volume[i] / (4./3. * mjPI * pow(g->size[0], 3)); - } - } - } - - // add isometry constraints - if (dim==2) { - char txt0[100], txt1[100], txt2[100]; - std::vector> edge; - - // create edges - for (int i=0; ispec, &def[mjCOMPKIND_TENDON].spec); - mjs_setDefault(ten->element, &model->Default()->spec); - mjs_setString(ten->name, txt0); - ten->group = 4; - mjs_wrapSite(ten, txt1); - mjs_wrapSite(ten, txt2); - - // add equality constraint - mjsEquality* eq = mjs_addEquality(&model->spec, &def[mjCOMPKIND_TENDON].spec); - mjs_setDefault(eq->element, &model->Default()->spec); - eq->type = mjEQ_TENDON; - mjs_setString(eq->name1, mjs_getString(ten->name)); - } - } - - if (skin && dim==3) { - MakeSkin3(model); - } - - if (skin && dim==2) { - if (skinsubgrid>0) { - MakeSkin2Subgrid(model, skininflate); - } else { - MakeSkin2(model, skininflate); - } } return true; @@ -1303,43 +1150,6 @@ void mjCComposite::MakeSkin2(mjCModel* model, mjtNum inflate) { skin->inflate = inflate; skin->group = skingroup; - // copy skin from existing mesh - if (type==mjCOMPTYPE_PARTICLE && username.empty()) { - std::vector skinface; - skinface = StringToVector(userface); - int nvert = uservert.size()/3; - - for (int j=0; j<2; j++) { - for (int i=0; ibodyname, txt); - bindpos.push_back(0); - bindpos.push_back(0); - bindpos.push_back(0); - bindquat.push_back(1); - bindquat.push_back(0); - bindquat.push_back(0); - bindquat.push_back(0); - - vertid.push_back({j*nvert+i}); - vertweight.push_back({1}); - } - - for (int i=0; i uservert; // user-specified vertex positions - std::string userface; // connectivity double size[3]; // rope size (meaning depends on the shape) mjtCompShape curve[3]; // geometric shape diff --git a/src/xml/xml_native_reader.cc b/src/xml/xml_native_reader.cc index ea16835f..ba089c32 100644 --- a/src/xml/xml_native_reader.cc +++ b/src/xml/xml_native_reader.cc @@ -296,8 +296,8 @@ const char* MJCF[nMJCF][mjXATTRNUM] = { {"<"}, {"config", "*", "2", "key", "value"}, {">"}, - {"composite", "*", "13", "prefix", "type", "count", "spacing", "offset", - "flatinertia", "solrefsmooth", "solimpsmooth", "vertex", "face", + {"composite", "*", "12", "prefix", "type", "count", "spacing", "offset", + "flatinertia", "solrefsmooth", "solimpsmooth", "vertex", "initial", "curve", "size"}, {"<"}, {"joint", "*", "17", "kind", "group", "stiffness", "damping", "armature", @@ -2371,9 +2371,6 @@ void mjXReader::OneComposite(XMLElement* elem, mjsBody* body, mjsDefault* def) { comp.uservert = std::move(uservert.value()); } - // shell - ReadAttrTxt(elem, "face", comp.userface); - // process curve string std::istringstream iss(curves); int i = 0; diff --git a/test/benchmark/engine_util_sparse_benchmark_test.cc b/test/benchmark/engine_util_sparse_benchmark_test.cc index f8addc94..80839276 100644 --- a/test/benchmark/engine_util_sparse_benchmark_test.cc +++ b/test/benchmark/engine_util_sparse_benchmark_test.cc @@ -348,7 +348,7 @@ void ABSL_ATTRIBUTE_NOINLINE mulMatVecSparse_8(mjtNum* res, // ----------------------------- benchmark ------------------------------------ static void BM_MatVecSparse(benchmark::State& state, int unroll) { - static mjModel* m = LoadModelFromPath("plugin/elasticity/flag.xml"); + static mjModel* m = LoadModelFromPath("plugin/elasticity/flag_flex.xml"); mjData* d = mj_makeData(m); // warm-up rollout to get a typical state diff --git a/test/benchmark/parse_benchmark_test.cc b/test/benchmark/parse_benchmark_test.cc index be01e33f..f74ed03f 100644 --- a/test/benchmark/parse_benchmark_test.cc +++ b/test/benchmark/parse_benchmark_test.cc @@ -70,7 +70,7 @@ static void run_parse_benchmark(const std::string xml_path, // run_parse_benchmark). void ABSL_ATTRIBUTE_NO_TAIL_CALL BM_ParseFlagPlugin(benchmark::State& state) { - run_parse_benchmark(GetModelPath("plugin/elasticity/flag.xml"), state); + run_parse_benchmark(GetModelPath("plugin/elasticity/flag_flex.xml"), state); } BENCHMARK(BM_ParseFlagPlugin); diff --git a/test/benchmark/step_benchmark_test.cc b/test/benchmark/step_benchmark_test.cc index d2b6963d..dbb98432 100644 --- a/test/benchmark/step_benchmark_test.cc +++ b/test/benchmark/step_benchmark_test.cc @@ -74,7 +74,7 @@ static void run_step_benchmark(const mjModel* model, benchmark::State& state) { void ABSL_ATTRIBUTE_NO_TAIL_CALL BM_StepFlagPlugin(benchmark::State& state) { MujocoErrorTestGuard guard; - static mjModel* model = LoadModelFromPath("plugin/elasticity/flag.xml"); + static mjModel* model = LoadModelFromPath("plugin/elasticity/flag_flex.xml"); run_step_benchmark(model, state); } BENCHMARK(BM_StepFlagPlugin); diff --git a/test/plugin/elasticity/elasticity_test.cc b/test/plugin/elasticity/elasticity_test.cc index 199f3d0b..2cdd410c 100644 --- a/test/plugin/elasticity/elasticity_test.cc +++ b/test/plugin/elasticity/elasticity_test.cc @@ -184,12 +184,13 @@ TEST_F(ElasticityTest, InvalidThickness) { - - + - + + )"; @@ -197,6 +198,7 @@ TEST_F(ElasticityTest, InvalidThickness) { char error[1024] = {0}; mjModel* m = LoadModelFromString(xml, error, sizeof(error)); ASSERT_THAT(m, testing::IsNull()); + EXPECT_THAT(error, ::testing::HasSubstr("Invalid parameter")); } // -------------------------------- solid -----------------------------------