Skip to content

Commit 8ecf4a1

Browse files
saran-tcopybara-github
authored andcommitted
Dynamically allocate contact and efc_ arrays on a new memory arena.
- Add private function `mj_arenaAlloc`. This is used internally to allocate memory from the arena. - Add private function `mj_nefc` to count constraints. This function returns a tight upper bound on `d->nefc`. The number of counted constraints can be slightly bigger than exact `d->nefc` in the case of constraints with empty Jacobian, as when placing a frictional tendon between two world sites. - Add new `memory` attribute to the `size` XML element for specification of arena memory size. This attribute is mutually exclusive with `nstack` and `njmax` specifications, which are now deprecated (but left around for the time being for legacy compatibility). - Move `d->stack` to the end of the new arena space. The stack now grows in reverse from the end. PiperOrigin-RevId: 479341539 Change-Id: I27f67d524607db71e24f714dc96b221c0448795e
1 parent f14b37a commit 8ecf4a1

3 files changed

Lines changed: 3 additions & 66 deletions

File tree

dm_control/composer/initializers/prop_initializer_test.py

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@
2020
from dm_control import composer
2121
from dm_control import mjcf
2222
from dm_control.composer.initializers import prop_initializer
23-
from dm_control.composer.variation import deterministic
2423
from dm_control.composer.variation import distributions
2524
from dm_control.entities import props
26-
from dm_control.rl import control
2725
import numpy as np
2826

2927

@@ -158,62 +156,6 @@ def test_ignore_contacts_with_entities(self):
158156
ignore_contacts_with_entities=None)
159157
self.assertNoContactsInvolvingEntities(physics, spheres)
160158

161-
def test_exception_if_contact_buffer_always_full(self):
162-
max_attempts_per_prop = 2
163-
radius = 0.1
164-
num_spheres = 5
165-
physics, spheres = _make_spheres(num_spheres=num_spheres,
166-
radius=radius, nconmax=1)
167-
168-
candidate_positions = np.multiply.outer(
169-
np.arange(num_spheres * max_attempts_per_prop), [radius * 2.01, 0, 0])
170-
171-
# If we only place the first sphere then the others will all be overlapping
172-
# at the origin, so we get an error due to filling the contact buffer.
173-
prop_placer_failure = prop_initializer.PropPlacer(
174-
props=[spheres[0]],
175-
position=deterministic.Sequence(candidate_positions),
176-
ignore_collisions=False,
177-
max_attempts_per_prop=max_attempts_per_prop)
178-
with self.assertRaises(control.PhysicsError):
179-
prop_placer_failure(physics, random_state=np.random.RandomState(0))
180-
181-
physics, spheres = _make_spheres(num_spheres=num_spheres,
182-
radius=radius, nconmax=1)
183-
184-
# If we place all of the spheres then we can find a configuration where they
185-
# are non-colliding, so the contact buffer is not full when the initializer
186-
# returns.
187-
prop_placer = prop_initializer.PropPlacer(
188-
props=spheres,
189-
position=deterministic.Sequence(candidate_positions),
190-
ignore_collisions=False,
191-
max_attempts_per_prop=max_attempts_per_prop)
192-
prop_placer(physics, random_state=np.random.RandomState(0))
193-
194-
def test_no_exception_if_contact_buffer_transiently_full(self):
195-
max_attempts_per_prop = 2
196-
radius = 0.1
197-
num_spheres = 3
198-
physics, spheres = _make_spheres(num_spheres=num_spheres,
199-
radius=radius, nconmax=1)
200-
fixed_positions = [[-radius * 1.01, 0., 0],
201-
[radius * 1.01, 0., 0.]]
202-
for sphere, position in zip(spheres[:2], fixed_positions):
203-
sphere.set_pose(physics, position=position)
204-
205-
candidate_positions = [
206-
[0., 0., 0.], # Collides with both fixed spheres.
207-
[5 * radius, 0., 0.]] # Does not collide with either sphere.
208-
209-
# The first candidate position transiently fills the contact buffer.
210-
prop_placer = prop_initializer.PropPlacer(
211-
props=spheres[2:],
212-
position=deterministic.Sequence(candidate_positions),
213-
ignore_collisions=False,
214-
max_attempts_per_prop=max_attempts_per_prop)
215-
prop_placer(physics, random_state=np.random.RandomState(0))
216-
217159
@parameterized.parameters([False, True])
218160
def test_settle_physics(self, settle_physics):
219161
radius = 0.1

dm_control/locomotion/soccer/task.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def __init__(
4545
observables=None,
4646
disable_walker_contacts=False,
4747
nconmax_per_player=200,
48-
njmax_per_player=200,
48+
njmax_per_player=400,
4949
control_timestep=0.025,
5050
tracking_cameras=(),
5151
):
@@ -229,7 +229,7 @@ def __init__(self,
229229
observables=None,
230230
disable_walker_contacts=False,
231231
nconmax_per_player=200,
232-
njmax_per_player=200,
232+
njmax_per_player=400,
233233
control_timestep=0.025,
234234
tracking_cameras=()):
235235
"""See base class."""

dm_control/mujoco/wrapper/core_test.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
from dm_control import _render
2525
from dm_control.mujoco.testing import assets
2626
from dm_control.mujoco.wrapper import core
27-
import mock
2827
import mujoco
2928
import numpy as np
3029

@@ -92,11 +91,7 @@ def testLoadXML(self):
9291
# simulation step.
9392
model = core.MjModel.from_xml_string(xml_with_warning)
9493
data = core.MjData(model)
95-
with mock.patch.object(core, "logging") as mock_logging:
96-
mujoco.mj_step(model.ptr, data.ptr)
97-
mock_logging.warning.assert_called_once_with(
98-
"Pre-allocated constraint buffer is full. Increase njmax above 2. "
99-
"Time = 0.0000.")
94+
mujoco.mj_step(model.ptr, data.ptr)
10095

10196
def testLoadXMLWithAssetsFromString(self):
10297
core.MjModel.from_xml_string(MODEL_WITH_ASSETS, assets=ASSETS)

0 commit comments

Comments
 (0)