diff --git a/doc/includes/references.h b/doc/includes/references.h index 6a30e704..548e2703 100644 --- a/doc/includes/references.h +++ b/doc/includes/references.h @@ -291,8 +291,8 @@ struct mjData_ { int* ten_wrapnum; // number of wrap points in path (ntendon x 1) int* ten_J_rownnz; // number of non-zeros in Jacobian row (ntendon x 1) int* ten_J_rowadr; // row start address in colind array (ntendon x 1) - int* ten_J_colind; // column indices in sparse Jacobian (nJten x 1) - mjtNum* ten_J; // tendon Jacobian (nJten x 1) + int* ten_J_colind; // column indices in sparse Jacobian (ntendon x nv) + mjtNum* ten_J; // tendon Jacobian (ntendon x nv) mjtNum* ten_length; // tendon lengths (ntendon x 1) int* wrap_obj; // geom id; -1: site; -2: pulley (nwrap x 2) mjtNum* wrap_xpos; // Cartesian 3D points in all paths (nwrap x 6) @@ -1096,7 +1096,6 @@ struct mjModel_ { // sizes set after mjModel construction mjtSize nnames_map; // number of slots in the names hash map mjtSize nJmom; // number of non-zeros in sparse actuator_moment matrix - mjtSize nJten; // number of non-zeros in sparse ten_J matrix mjtSize ngravcomp; // number of bodies with nonzero gravcomp mjtSize nemax; // number of potential equality-constraint rows mjtSize njmax; // number of available rows in constraint Jacobian (legacy) diff --git a/include/mujoco/mjdata.h b/include/mujoco/mjdata.h index 314dfc0e..839602d5 100644 --- a/include/mujoco/mjdata.h +++ b/include/mujoco/mjdata.h @@ -325,8 +325,8 @@ struct mjData_ { int* ten_wrapnum; // number of wrap points in path (ntendon x 1) int* ten_J_rownnz; // number of non-zeros in Jacobian row (ntendon x 1) int* ten_J_rowadr; // row start address in colind array (ntendon x 1) - int* ten_J_colind; // column indices in sparse Jacobian (nJten x 1) - mjtNum* ten_J; // tendon Jacobian (nJten x 1) + int* ten_J_colind; // column indices in sparse Jacobian (ntendon x nv) + mjtNum* ten_J; // tendon Jacobian (ntendon x nv) mjtNum* ten_length; // tendon lengths (ntendon x 1) int* wrap_obj; // geom id; -1: site; -2: pulley (nwrap x 2) mjtNum* wrap_xpos; // Cartesian 3D points in all paths (nwrap x 6) diff --git a/include/mujoco/mjmodel.h b/include/mujoco/mjmodel.h index 20151f48..7dd3c64a 100644 --- a/include/mujoco/mjmodel.h +++ b/include/mujoco/mjmodel.h @@ -754,7 +754,6 @@ struct mjModel_ { // sizes set after mjModel construction mjtSize nnames_map; // number of slots in the names hash map mjtSize nJmom; // number of non-zeros in sparse actuator_moment matrix - mjtSize nJten; // number of non-zeros in sparse ten_J matrix mjtSize ngravcomp; // number of bodies with nonzero gravcomp mjtSize nemax; // number of potential equality-constraint rows mjtSize njmax; // number of available rows in constraint Jacobian (legacy) diff --git a/include/mujoco/mjxmacro.h b/include/mujoco/mjxmacro.h index f0d2f808..4780e834 100644 --- a/include/mujoco/mjxmacro.h +++ b/include/mujoco/mjxmacro.h @@ -240,7 +240,6 @@ X( npaths ) \ X( nnames_map ) \ X( nJmom ) \ - X( nJten ) \ X( ngravcomp ) \ X( nemax ) \ X( njmax ) \ @@ -799,6 +798,11 @@ //-------------------------------- mjData ---------------------------------------------------------- +// define symbols needed in MJDATA_POINTERS (corresponding to number of columns) +#define MJDATA_POINTERS_PREAMBLE( m ) \ + int nv = m->nv; + + // pointer fields of mjData // XNV means that the field is not required to construct mjvScene // (by default we define XNV to be the same as X) @@ -851,8 +855,8 @@ X ( int, ten_wrapnum, ntendon, 1 ) \ X ( int, ten_J_rownnz, ntendon, 1 ) \ X ( int, ten_J_rowadr, ntendon, 1 ) \ - X ( int, ten_J_colind, nJten, 1 ) \ - X ( mjtNum, ten_J, nJten, 1 ) \ + X ( int, ten_J_colind, ntendon, MJ_M(nv) ) \ + X ( mjtNum, ten_J, ntendon, MJ_M(nv) ) \ X ( mjtNum, ten_length, ntendon, 1 ) \ X ( int, wrap_obj, nwrap, 2 ) \ X ( mjtNum, wrap_xpos, nwrap, 6 ) \ diff --git a/mjx/mujoco/mjx/_src/io.py b/mjx/mujoco/mjx/_src/io.py index 108458e2..67038a63 100644 --- a/mjx/mujoco/mjx/_src/io.py +++ b/mjx/mujoco/mjx/_src/io.py @@ -768,8 +768,8 @@ def _make_data_c( 'flexedge_length': (nflexedge, float_), 'ten_J_rownnz': (m.ntendon, np.int32), 'ten_J_rowadr': (m.ntendon, np.int32), - 'ten_J_colind': (m.nJten, np.int32), - 'ten_J': (m.nJten, float_), + 'ten_J_colind': (m.ntendon, m.nv, np.int32), + 'ten_J': (m.ntendon, m.nv, float_), 'ten_wrapadr': (m.ntendon, np.int32), 'ten_wrapnum': (m.ntendon, np.int32), 'wrap_obj': (m.nwrap, 2, np.int32), @@ -1099,7 +1099,7 @@ def _put_data_jax( # MJX does not support islanding, so only transfer the first solver_niter impl_fields['solver_niter'] = impl_fields['solver_niter'][0] - # convert sparse actuator_moment to dense matrix + # convert sparse representation of actuator_moment to dense matrix moment = np.zeros((m.nu, m.nv)) mujoco.mju_sparse2dense( moment, @@ -1110,22 +1110,6 @@ def _put_data_jax( ) impl_fields['actuator_moment'] = moment - # convert ten_J to dense matrix - if mujoco.mj_isSparse(m): - ten_J = np.zeros((m.ntendon, m.nv)) - mujoco.mju_sparse2dense( - ten_J, - d.ten_J, - d.ten_J_rownnz, - d.ten_J_rowadr, - d.ten_J_colind, - ) - elif m.ntendon: - ten_J = d.ten_J.reshape((m.ntendon, m.nv)) - else: - ten_J = np.zeros((m.ntendon, m.nv)) - impl_fields['ten_J'] = ten_J - contact, contact_map = _put_contact(d.contact, dim, efc_address) # pad efc fields: MuJoCo efc arrays are sparse for inactive constraints. @@ -1584,29 +1568,6 @@ def _get_data_into( result_i.actuator_moment[:] = actuator_moment continue - # MuJoCo ten_J is sparse, MJX uses a dense representation. - if field.name == 'ten_J': - ten_j_rownnz = np.zeros(m.ntendon, dtype=np.int32) - ten_j_rowadr = np.zeros(m.ntendon, dtype=np.int32) - ten_j_colind = np.zeros(m.nJten, dtype=np.int32) - ten_j = np.zeros(m.nJten) - if m.ntendon: - if d_i.impl == types.Impl.JAX: - mujoco.mju_dense2sparse( - ten_j, - d_i._impl.ten_J, - ten_j_rownnz, - ten_j_rowadr, - ten_j_colind, - ) - else: - ten_j = d_i._impl.ten_J - result_i.ten_J_rownnz[:] = ten_j_rownnz - result_i.ten_J_rowadr[:] = ten_j_rowadr - result_i.ten_J_colind[:] = ten_j_colind - result_i.ten_J[:] = ten_j - continue - if hasattr(d_i._impl, field.name): value = getattr(d_i._impl, field.name) else: diff --git a/mjx/mujoco/mjx/_src/smooth_test.py b/mjx/mujoco/mjx/_src/smooth_test.py index 667b3d63..302547da 100644 --- a/mjx/mujoco/mjx/_src/smooth_test.py +++ b/mjx/mujoco/mjx/_src/smooth_test.py @@ -121,9 +121,7 @@ class SmoothTest(absltest.TestCase): mujoco.mj_forward(m, d) # tendon dx = jax.jit(mjx.tendon)(mx, mjx.put_data(m, d)) - # with dense jacobian mode, d.ten_J is already dense (ntendon*nv,), just reshape - ten_J = d.ten_J.reshape((m.ntendon, m.nv)) - _assert_eq(ten_J, dx._impl.ten_J, 'ten_J') + _assert_attr_eq(d, dx._impl, 'ten_J') _assert_attr_eq(d, dx, 'ten_length') # transmission dx = jax.jit(mjx.transmission)(mx, dx) @@ -397,20 +395,7 @@ class TendonTest(parameterized.TestCase): dx = jax.jit(mjx.forward)(mx, dx) _assert_eq(d.ten_length, dx.ten_length, 'ten_length') - # convert ten_J for comparison based on jacobian mode - if mujoco.mj_isSparse(m): - ten_J = np.zeros((m.ntendon, m.nv)) - mujoco.mju_sparse2dense( - ten_J, - d.ten_J, - d.ten_J_rownnz, - d.ten_J_rowadr, - d.ten_J_colind, - ) - else: - # dense mode: just reshape - ten_J = d.ten_J.reshape((m.ntendon, m.nv)) - _assert_eq(ten_J, dx._impl.ten_J, 'ten_J') + _assert_eq(d.ten_J, dx._impl.ten_J, 'ten_J') _assert_eq(d.ten_wrapnum, dx._impl.ten_wrapnum, 'ten_wrapnum') _assert_eq(d.ten_wrapadr, dx._impl.ten_wrapadr, 'ten_wrapadr') _assert_eq(d.wrap_obj, dx._impl.wrap_obj, 'wrap_obj') diff --git a/mjx/mujoco/mjx/_src/types.py b/mjx/mujoco/mjx/_src/types.py index d7521a88..81c5ae2c 100644 --- a/mjx/mujoco/mjx/_src/types.py +++ b/mjx/mujoco/mjx/_src/types.py @@ -722,7 +722,6 @@ class Model(PyTreeNode): nC: number of non-zeros in C matrix nD: number of non-zeros in D matrix nJmom: number of non-zeros in Jacobian momentum matrix - nJten: number of non-zeros in sparse tendon Jacobian ngravcomp: number of bodies with nonzero gravcomp nuserdata: number of elements in userdata nsensordata: number of elements in sensor data vector @@ -773,7 +772,6 @@ class Model(PyTreeNode): nC: int # pylint:disable=invalid-name nD: int # pylint:disable=invalid-name nJmom: int # pylint:disable=invalid-name - nJten: int # pylint:disable=invalid-name ngravcomp: int nuserdata: int nsensordata: int diff --git a/mjx/mujoco/mjx/third_party/mujoco_warp/_src/io.py b/mjx/mujoco/mjx/third_party/mujoco_warp/_src/io.py index 8990aab3..2febee1f 100644 --- a/mjx/mujoco/mjx/third_party/mujoco_warp/_src/io.py +++ b/mjx/mujoco/mjx/third_party/mujoco_warp/_src/io.py @@ -1169,18 +1169,7 @@ def get_data_into( # tendon result.ten_length[:] = d.ten_length.numpy()[world_id] - # TODO(team): remove after mjwarp depends on mujoco > 3.4.0 in pyproject.toml - if BLEEDING_EDGE_MUJOCO: - ten_J = d.ten_J.numpy()[world_id] - mujoco.mju_dense2sparse( - result.ten_J, - ten_J, - result.ten_J_rownnz, - result.ten_J_rowadr, - result.ten_J_colind, - ) - else: - result.ten_J[:] = d.ten_J.numpy()[world_id] + result.ten_J[:] = d.ten_J.numpy()[world_id] result.ten_wrapadr[:] = d.ten_wrapadr.numpy()[world_id] result.ten_wrapnum[:] = d.ten_wrapnum.numpy()[world_id] result.wrap_obj[:] = d.wrap_obj.numpy()[world_id] diff --git a/mjx/mujoco/mjx/warp/forward_test.py b/mjx/mujoco/mjx/warp/forward_test.py index 020e924a..aa0700a6 100644 --- a/mjx/mujoco/mjx/warp/forward_test.py +++ b/mjx/mujoco/mjx/warp/forward_test.py @@ -149,8 +149,7 @@ class ForwardTest(parameterized.TestCase): tu.assert_attr_eq(dx, d, 'cam_xpos') tu.assert_eq(dx.cam_xmat, d.cam_xmat.reshape((-1, 3, 3)), 'cam_xmat') tu.assert_attr_eq(dx, d, 'ten_length') - ten_J = d.ten_J.reshape((m.ntendon, m.nv)) - tu.assert_eq(dx._impl.ten_J, ten_J, 'ten_J') + tu.assert_attr_eq(dx._impl, d, 'ten_J') tu.assert_attr_eq(dx._impl, d, 'ten_wrapadr') tu.assert_attr_eq(dx._impl, d, 'ten_wrapnum') tu.assert_attr_eq(dx._impl, d, 'wrap_xpos') diff --git a/python/mujoco/introspect/structs.py b/python/mujoco/introspect/structs.py index c8f6774f..8a2fc4a8 100644 --- a/python/mujoco/introspect/structs.py +++ b/python/mujoco/introspect/structs.py @@ -1242,11 +1242,6 @@ STRUCTS: Mapping[str, StructDecl] = dict([ type=ValueType(name='mjtSize'), doc='number of non-zeros in sparse actuator_moment matrix', ), - StructFieldDecl( - name='nJten', - type=ValueType(name='mjtSize'), - doc='number of non-zeros in sparse ten_J matrix', - ), StructFieldDecl( name='ngravcomp', type=ValueType(name='mjtSize'), @@ -5834,7 +5829,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([ inner_type=ValueType(name='int'), ), doc='column indices in sparse Jacobian', - array_extent=('nJten',), + array_extent=('ntendon', 'nv'), ), StructFieldDecl( name='ten_J', @@ -5842,7 +5837,7 @@ STRUCTS: Mapping[str, StructDecl] = dict([ inner_type=ValueType(name='mjtNum'), ), doc='tendon Jacobian', - array_extent=('nJten',), + array_extent=('ntendon', 'nv'), ), StructFieldDecl( name='ten_length', diff --git a/python/mujoco/structs_wrappers.cc b/python/mujoco/structs_wrappers.cc index 307d611e..8da1b115 100644 --- a/python/mujoco/structs_wrappers.cc +++ b/python/mujoco/structs_wrappers.cc @@ -747,6 +747,7 @@ void MjDataWrapper::Serialize(std::ostream& output) const { // Write buffer and arena contents { + MJDATA_POINTERS_PREAMBLE((this->model_->get())) #define X(type, name, nr, nc) \ WriteBytes(output, ptr_->name, \ @@ -826,6 +827,7 @@ MjDataWrapper MjDataWrapper::Deserialize(std::istream& input) { // Read buffer and arena contents { + MJDATA_POINTERS_PREAMBLE((&m)) #define X(type, name, nr, nc) \ ReadBytes(input, d->name, sizeof(type) * (m.nr) * (nc)); diff --git a/simulate/simulate.cc b/simulate/simulate.cc index 2580c45a..cd31a36e 100644 --- a/simulate/simulate.cc +++ b/simulate/simulate.cc @@ -669,6 +669,9 @@ void UpdateWatch(mj::Simulate* sim, const mjModel* m, const mjData* d) { sim->ui0.sect[SECT_WATCH].item[2].multi.nelem = 1; mju::strcpy_arr(sim->ui0.sect[SECT_WATCH].item[2].multi.name[0], "invalid field"); + // prepare symbols needed by xmacro + MJDATA_POINTERS_PREAMBLE(m); + // find specified field in mjData arrays, update value #define X(TYPE, NAME, NR, NC) \ if (!mju::strcmp_arr(#NAME, sim->field) && \ diff --git a/src/engine/engine_io.c b/src/engine/engine_io.c index 512c7661..8bb97d15 100644 --- a/src/engine/engine_io.c +++ b/src/engine/engine_io.c @@ -224,7 +224,7 @@ void mj_makeModel(mjModel** dest, // CHECK SIZE PARAMETERS { // dummy variables for MJMODEL_SIZES set after mjModel construction - int nnames_map = 0, nJmom = 0, nJten = 0, ngravcomp = 0, nemax = 0, njmax = 0, nconmax=0; + int nnames_map=0, nJmom=0, ngravcomp=0, nemax=0, njmax=0, nconmax=0; int nuserdata=0, nsensordata=0, npluginstate=0, nhistory=0, narena=0, nbuffer=0; // sizes must be non-negative and fit in int, except for the byte arrays texdata and textdata @@ -240,10 +240,10 @@ void mj_makeModel(mjModel** dest, return; \ } MJMODEL_SIZES -#undef X + #undef X // suppress unused variable warnings - (void)nnames_map; (void)nJmom; (void)nJten; (void)ngravcomp; (void)nemax; (void)njmax; (void)nconmax; + (void)nnames_map; (void)nJmom; (void)ngravcomp; (void)nemax; (void)njmax; (void)nconmax; (void)nuserdata; (void)nsensordata; (void)npluginstate; (void)nhistory; (void)narena; (void)nbuffer; } @@ -964,6 +964,9 @@ void mj_makeDofDofMaps(int nv, int nM, int nC, int nD, static void mj_setPtrData(const mjModel* m, mjData* d) { char* ptr = (char*)d->buffer; + // prepare symbols needed by xmacro + MJDATA_POINTERS_PREAMBLE(m); + // assign pointers with padding #define X(type, name, nr, nc) \ d->name = (type*)(ptr + SKIP((intptr_t)ptr)); \ @@ -1044,6 +1047,9 @@ void mj_makeRawData(mjData** dest, const mjModel* m) { mjERROR("could not allocate mjData"); } + // prepare symbols needed by xmacro + MJDATA_POINTERS_PREAMBLE(m); + // compute buffer size d->nbuffer = 0; d->buffer = d->arena = NULL; @@ -1154,6 +1160,7 @@ mjData* mj_copyDataVisual(mjData* dest, const mjModel* m, const mjData* src, int // copy buffer { + MJDATA_POINTERS_PREAMBLE(m) if (flg_all) { #define X(type, name, nr, nc) \ memcpy((char*)dest->name, (const char*)src->name, sizeof(type)*(m->nr)*nc); @@ -1339,6 +1346,7 @@ static void _resetData(const mjModel* m, mjData* d, unsigned char debug_value) { #ifdef ADDRESS_SANITIZER { #define X(type, name, nr, nc) memset(d->name, (int)debug_value, sizeof(type)*(m->nr)*(nc)); + MJDATA_POINTERS_PREAMBLE(m) MJDATA_POINTERS #undef X } diff --git a/src/experimental/platform/helpers.cc b/src/experimental/platform/helpers.cc index add021f9..6ec9ec9e 100644 --- a/src/experimental/platform/helpers.cc +++ b/src/experimental/platform/helpers.cc @@ -100,6 +100,7 @@ void SaveToWebp(int width, int height, const std::byte* data, const void* GetValue(const mjModel* model, const mjData* data, const char* field, int index) { + MJDATA_POINTERS_PREAMBLE(model); #define X(TYPE, NAME, NR, NC) \ if (!std::strcmp(#NAME, field) && !std::strcmp(#TYPE, "mjtNum")) { \ if (index >= 0 && index < model->NR * NC) { \ diff --git a/src/user/user_model.cc b/src/user/user_model.cc index 05fb2e6e..a7649762 100644 --- a/src/user/user_model.cc +++ b/src/user/user_model.cc @@ -3226,16 +3226,7 @@ int mjCModel::CountNJmom(const mjModel* m) { return count; } -// compute non-zeros in ten_J matrix -int mjCModel::CountNJten(const mjModel* m) { - int nv = m->nv; - int ntendon = m->ntendon; - // conservative upper bound: each tendon can have at most nv non-zeros - // TODO(taylorhowell): compute tighter bound - int count = ntendon * nv; - return count; -} // copy objects outside kinematic tree void mjCModel::CopyObjects(mjModel* m) { @@ -5046,9 +5037,6 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) { // compute non-zeros in actuator_moment m->nJmom = nJmom = CountNJmom(m); - // compute non-zeros in ten_J - m->nJten = nJten = CountNJten(m); - // scale mass if (compiler.settotalmass > 0) { mj_setTotalmass(m, compiler.settotalmass); diff --git a/src/user/user_model.h b/src/user/user_model.h index 93e4d3f4..e2377016 100644 --- a/src/user/user_model.h +++ b/src/user/user_model.h @@ -130,7 +130,6 @@ class mjCModel_ : public mjsElement { mjtSize nC; // number of non-zeros in reduced sparse dof-dof matrix mjtSize nD; // number of non-zeros in sparse dof-dof matrix mjtSize nJmom; // number of non-zeros in sparse actuator_moment matrix - mjtSize nJten; // number of non-zeros in sparse ten_J matrix // statistics, as computed by mj_setConst double meaninertia_auto; // mean diagonal inertia, as computed by mj_setConst @@ -369,7 +368,6 @@ class mjCModel : public mjCModel_, private mjSpec { void FinalizeSimple(mjModel* m); // finalize simple bodies/dofs including tendon information void CopyPlugins(mjModel*); // copy plugin data int CountNJmom(const mjModel* m); // compute number of non-zeros in actuator_moment matrix - int CountNJten(const mjModel* m); // compute number of non-zeros in ten_J matrix // remove plugins that are not referenced by any object void RemovePlugins(); diff --git a/test/engine/engine_core_smooth_test.cc b/test/engine/engine_core_smooth_test.cc index 53f36b38..247f453f 100644 --- a/test/engine/engine_core_smooth_test.cc +++ b/test/engine/engine_core_smooth_test.cc @@ -73,6 +73,7 @@ TEST_F(CoreSmoothTest, MjDataWorldBodyValuesAreInitialized) { mj_rnePostConstraint(model, data); { + MJDATA_POINTERS_PREAMBLE(model) #define X(type, name, d0, d1) \ if constexpr (std::string_view(#d0) == "nbody") { \ absl::Span values(data->name, model->d0 * d1); \ diff --git a/test/engine/engine_forward_test.cc b/test/engine/engine_forward_test.cc index 58e0fe73..ccccdc0d 100644 --- a/test/engine/engine_forward_test.cc +++ b/test/engine/engine_forward_test.cc @@ -725,6 +725,7 @@ TEST_F(ForwardTest, NormalizeQuats) { mj_step(model, data_n); // expect everything to match + MJDATA_POINTERS_PREAMBLE(model) #define X(type, name, nr, nc) \ for (int i = 0; i < model->nr; i++) \ for (int j = 0; j < nc; j++) \ diff --git a/test/engine/engine_thread_test.cc b/test/engine/engine_thread_test.cc index fd4ceae3..7d428c06 100644 --- a/test/engine/engine_thread_test.cc +++ b/test/engine/engine_thread_test.cc @@ -71,6 +71,7 @@ TEST_F(ThreadTest, SingleAndMultiThreadedMatch) { // compare the mjData's. { + MJDATA_POINTERS_PREAMBLE((model)) #define X(type, name, nr, nc) \ EXPECT_EQ(std::memcmp(data->name, data_threaded->name, \ sizeof(type)*(model->nr)*(nc)), \ @@ -126,6 +127,7 @@ TEST_F(ThreadTest, IslandSingleAndMultiThreadedMatch) { // compare the mjData's. { + MJDATA_POINTERS_PREAMBLE((model)) #define X(type, name, nr, nc) \ EXPECT_EQ(std::memcmp(data->name, data_threaded->name, \ sizeof(type)*(model->nr)*(nc)), \ diff --git a/unity/Runtime/Bindings/MjBindings.cs b/unity/Runtime/Bindings/MjBindings.cs index d95f57a9..119de775 100644 --- a/unity/Runtime/Bindings/MjBindings.cs +++ b/unity/Runtime/Bindings/MjBindings.cs @@ -5371,7 +5371,6 @@ public unsafe struct mjModel_ { public Int64 npaths; public Int64 nnames_map; public Int64 nJmom; - public Int64 nJten; public Int64 ngravcomp; public Int64 nemax; public Int64 njmax; diff --git a/wasm/codegen/generated/bindings.cc b/wasm/codegen/generated/bindings.cc index c49629ee..48ff8013 100644 --- a/wasm/codegen/generated/bindings.cc +++ b/wasm/codegen/generated/bindings.cc @@ -4078,12 +4078,6 @@ struct MjModel { void set_nJmom(int value) { ptr_->nJmom = static_cast(value); } - int nJten() const { - return static_cast(ptr_->nJten); - } - void set_nJten(int value) { - ptr_->nJten = static_cast(value); - } int ngravcomp() const { return static_cast(ptr_->ngravcomp); } @@ -6656,10 +6650,10 @@ struct MjData { return emscripten::val(emscripten::typed_memory_view(model->ntendon, ptr_->ten_J_rowadr)); } emscripten::val ten_J_colind() const { - return emscripten::val(emscripten::typed_memory_view(model->nJten, ptr_->ten_J_colind)); + return emscripten::val(emscripten::typed_memory_view(model->ntendon * model->nv, ptr_->ten_J_colind)); } emscripten::val ten_J() const { - return emscripten::val(emscripten::typed_memory_view(model->nJten, ptr_->ten_J)); + return emscripten::val(emscripten::typed_memory_view(model->ntendon * model->nv, ptr_->ten_J)); } emscripten::val ten_length() const { return emscripten::val(emscripten::typed_memory_view(model->ntendon, ptr_->ten_length)); @@ -11903,7 +11897,6 @@ EMSCRIPTEN_BINDINGS(mujoco_bindings) { .property("nJfe", &MjModel::nJfe, &MjModel::set_nJfe, reference()) .property("nJfv", &MjModel::nJfv, &MjModel::set_nJfv, reference()) .property("nJmom", &MjModel::nJmom, &MjModel::set_nJmom, reference()) - .property("nJten", &MjModel::nJten, &MjModel::set_nJten, reference()) .property("nM", &MjModel::nM, &MjModel::set_nM, reference()) .property("na", &MjModel::na, &MjModel::set_na, reference()) .property("name_actuatoradr", &MjModel::name_actuatoradr)