Skip to content

Commit 0e0c79e

Browse files
YilingQiaoduburcqa
authored andcommitted
[MISC] Reduce warning messages. (Genesis-Embodied-AI#1294)
1 parent 74fe8bd commit 0e0c79e

File tree

4 files changed

+71
-28
lines changed

4 files changed

+71
-28
lines changed

genesis/engine/solvers/rigid/rigid_solver_decomp.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ def _sanitize_sol_params(
4646
gs.logger.debug(f"Constraint solver time constant not specified. Using minimum value (`{min_timeconst:0.6g}`).")
4747
if ((timeconst > gs.EPS) & (timeconst + gs.EPS < min_timeconst)).any():
4848
gs.logger.warning(
49-
"Constraint solver time constant was increased to avoid numerical instability (from "
50-
f"`{timeconst.min():0.6g}` to `{min_timeconst:0.6g}`). Decrease simulation timestep to avoid "
51-
"altering the original value."
49+
"Constraint solver time constant should be greater than 2*subste_dt. timeconst is changed from "
50+
f"`{timeconst.min():0.6g}` to `{min_timeconst:0.6g}`). Decrease simulation timestep or "
51+
"increase timeconst to avoid altering the original value."
5252
)
5353
timeconst[:] = timeconst.clip(min_timeconst)
5454
dampratio[:] = dampratio.clip(0.0)
@@ -327,13 +327,11 @@ def _kernel_init_invweight(
327327
links_invweight: ti.types.ndarray(),
328328
dofs_invweight: ti.types.ndarray(),
329329
):
330-
ti.loop_config(serialize=self._para_level < gs.PARA_LEVEL.PARTIAL)
331330
for I in ti.grouped(self.links_info):
332331
for j in ti.static(range(2)):
333332
if self.links_info[I].invweight[j] < gs.EPS:
334333
self.links_info[I].invweight[j] = links_invweight[I[0], j]
335334

336-
ti.loop_config(serialize=self._para_level < gs.PARA_LEVEL.PARTIAL)
337335
for I in ti.grouped(self.dofs_info):
338336
if self.dofs_info[I].invweight < gs.EPS:
339337
self.dofs_info[I].invweight = dofs_invweight[I[0]]
@@ -481,7 +479,6 @@ def _kernel_init_dof_fields(
481479
dofs_kv: ti.types.ndarray(),
482480
dofs_force_range: ti.types.ndarray(),
483481
):
484-
ti.loop_config(serialize=self._para_level < gs.PARA_LEVEL.PARTIAL)
485482
for I in ti.grouped(self.dofs_info):
486483
i = I[0] # batching (if any) will be the second dim
487484

@@ -693,7 +690,6 @@ def _kernel_init_link_fields(
693690
links_inertial_mass: ti.types.ndarray(),
694691
links_entity_idx: ti.types.ndarray(),
695692
):
696-
ti.loop_config(serialize=self._para_level < gs.PARA_LEVEL.PARTIAL)
697693
for I in ti.grouped(self.links_info):
698694
i = I[0]
699695

@@ -725,7 +721,6 @@ def _kernel_init_link_fields(
725721
for j2 in ti.static(range(3)):
726722
self.links_info[I].inertial_i[j1, j2] = links_inertial_i[i, j1, j2]
727723

728-
ti.loop_config(serialize=self._para_level < gs.PARA_LEVEL.PARTIAL)
729724
for i, b in ti.ndrange(self.n_links, self._B):
730725
I = [i, b] if ti.static(self._options.batch_links_info) else i
731726

@@ -762,7 +757,6 @@ def _kernel_init_joint_fields(
762757
joints_dof_end: ti.types.ndarray(),
763758
joints_pos: ti.types.ndarray(),
764759
):
765-
ti.loop_config(serialize=self._para_level < gs.PARA_LEVEL.PARTIAL)
766760
for I in ti.grouped(self.joints_info):
767761
i = I[0]
768762

@@ -1789,7 +1783,6 @@ def detect_collision(self, env_idx=0):
17891783

17901784
@ti.kernel
17911785
def _kernel_forward_kinematics_links_geoms(self, envs_idx: ti.types.ndarray()):
1792-
ti.loop_config(serialize=self._para_level < gs.PARA_LEVEL.ALL)
17931786
for i_b in envs_idx:
17941787
self._func_forward_kinematics(i_b)
17951788
self._func_COM_links(i_b)

genesis/utils/misc.py

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,28 +45,76 @@ def raise_exception_from(msg="Something went wrong.", cause=None):
4545

4646

4747
class redirect_libc_stderr:
48+
"""
49+
Context-manager that temporarily redirects C / C++ std::cerr
50+
(i.e. the C `stderr` file descriptor 2) to a given Python
51+
file-like object’s fd.
52+
53+
Works on macOS, Linux (glibc / musl), and Windows (MSVCRT /
54+
Universal CRT ≥ VS2015).
55+
"""
56+
4857
def __init__(self, fd):
49-
self.fd = fd
50-
self.stderr_fileno = None
58+
self.fd = fd # Target destination
59+
self.stderr_fileno = None # Usually 2
5160
self.original_stderr_fileno = None
5261

62+
# --------------------------------------------------
63+
# Enter: duplicate stderr → tmp, dup2(target) → stderr
64+
# --------------------------------------------------
5365
def __enter__(self):
54-
# TODO: Add Linux and Windows support
55-
if sys.platform == "darwin":
66+
self.stderr_fileno = sys.stderr.fileno()
67+
# Keep a copy so we can restore later
68+
self.original_stderr_fileno = os.dup(self.stderr_fileno)
69+
sys.stderr.flush() # Flush Python buffers first
70+
71+
if os.name == "posix": # macOS, Linux, *BSD, …
5672
libc = ctypes.CDLL(None)
57-
self.stderr_fileno = sys.stderr.fileno()
58-
self.original_stderr_fileno = os.dup(self.stderr_fileno)
59-
sys.stderr.flush()
60-
libc.fflush(None)
73+
libc.fflush(None) # Flush all C stdio streams
6174
libc.dup2(self.fd.fileno(), self.stderr_fileno)
75+
elif os.name == "nt": # Windows
76+
msvcrt = ctypes.CDLL("msvcrt")
77+
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
78+
79+
msvcrt.fflush(None) # Flush CRT buffers
80+
# Duplicate: _dup2(new_fd, old_fd)
81+
msvcrt._dup2(self.fd.fileno(), self.stderr_fileno)
82+
83+
# Tell the OS so child APIs that use GetStdHandle( … )
84+
# see the new handle as well.
85+
STDERR_HANDLE = -12 # (DWORD) -12 == STD_ERROR_HANDLE
86+
new_os_handle = msvcrt._get_osfhandle(self.fd.fileno())
87+
kernel32.SetStdHandle(STDERR_HANDLE, new_os_handle)
88+
else:
89+
gs.logger.warning(f"Unsupported platform for redirecting libc stderr: {sys.platform}")
90+
91+
return self # Optional, enables `as` clause
6292

93+
# --------------------------------------------------
94+
# Exit: restore previous stderr, close the temp copy
95+
# --------------------------------------------------
6396
def __exit__(self, exc_type, exc_value, traceback):
64-
if self.stderr_fileno is not None:
97+
if self.stderr_fileno is None:
98+
return
99+
100+
if os.name == "posix":
65101
libc = ctypes.CDLL(None)
66102
sys.stderr.flush()
67103
libc.fflush(None)
68104
libc.dup2(self.original_stderr_fileno, self.stderr_fileno)
69-
os.close(self.original_stderr_fileno)
105+
elif os.name == "nt":
106+
msvcrt = ctypes.CDLL("msvcrt")
107+
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
108+
109+
sys.stderr.flush()
110+
msvcrt.fflush(None)
111+
msvcrt._dup2(self.original_stderr_fileno, self.stderr_fileno)
112+
113+
STDERR_HANDLE = -12
114+
orig_os_handle = msvcrt._get_osfhandle(self.original_stderr_fileno)
115+
kernel32.SetStdHandle(STDERR_HANDLE, orig_os_handle)
116+
117+
os.close(self.original_stderr_fileno)
70118
self.stderr_fileno = None
71119
self.original_stderr_fileno = None
72120

genesis/utils/mjcf.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import os
22
import xml.etree.ElementTree as ET
3-
from contextlib import redirect_stderr
3+
import contextlib
44
from pathlib import Path
55
from itertools import chain
66
from bisect import bisect_right
7+
import io
78

89
import numpy as np
910
import trimesh
@@ -112,7 +113,6 @@ def build_model(xml, discard_visual, default_armature=None, merge_fixed_links=Fa
112113
# Parse updated URDF file as a string
113114
data = ET.tostring(root, encoding="utf8")
114115
mj = mujoco.MjModel.from_xml_string(data)
115-
116116
# Special treatment for URDF
117117
if is_urdf_file:
118118
# Discard placeholder inertias that were used to avoid parsing failure
@@ -151,9 +151,10 @@ def parse_xml(morph, surface):
151151
# Build model from XML (either URDF or MJCF)
152152
mj = build_model(morph.file, not morph.visualization, morph.default_armature, merge_fixed_links, links_to_keep)
153153

154-
# Check if there is any tendon. Report a warning if so.
155-
if mj.ntendon:
156-
gs.logger.warning("(MJCF) Tendon not supported")
154+
# We have another more informative warning later so we suppress this one
155+
# gs.logger.warning(f"(MJCF) Approximating tendon by joint actuator for `{j_info['name']}`")
156+
# if mj.ntendon:
157+
# gs.logger.warning("(MJCF) Tendon not supported")
157158

158159
# Parse all geometries grouped by parent joint (or world)
159160
links_g_infos = parse_geoms(mj, morph.scale, surface, morph.file)
@@ -333,15 +334,16 @@ def parse_link(mj, i_l, scale):
333334
biasprm = mj.actuator_biasprm[i_a]
334335
if gainprm[1:].any() or biasprm[0]:
335336
gs.logger.warning(
336-
"(MJCF) Actuator control gain and bias parameters not supported. Using default values."
337+
"(MJCF) Actuator control gain and bias parameters not supported. "
338+
f"Using default values for joint `{j_info['name']}`"
337339
)
338340
actuator_kp = gu.default_dofs_kp(1)[0]
339341
actuator_kv = gu.default_dofs_kv(1)[0]
340342
elif gainprm[0] != -biasprm[1]:
341343
# Doing our best to approximate the expected behavior: g0 * p_target + b1 * p_mes + b2 * v_mes
342344
gs.logger.warning(
343345
"(MJCF) Actuator control gain and bias parameters cannot be reduced to a unique PD control "
344-
"position gain. Using max between gain and bias."
346+
f"position gain. Using max between gain and bias for joint `{j_info['name']}`."
345347
)
346348
actuator_kp = min(-gainprm[0], biasprm[1])
347349
actuator_kv = biasprm[2]

tests/test_rigid_physics.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1758,7 +1758,7 @@ def test_mesh_repair(convexify, show_viewer):
17581758

17591759

17601760
@pytest.mark.required
1761-
@pytest.mark.parametrize("euler", [(90, 0, 90), (74, 15, 90)])
1761+
@pytest.mark.parametrize("euler", [(90, 0, 90), (76, 15, 90)])
17621762
@pytest.mark.parametrize("backend", [gs.cpu, gs.gpu])
17631763
def test_convexify(euler, backend, show_viewer):
17641764
OBJ_OFFSET_X = 0.0 # 0.02

0 commit comments

Comments
 (0)