diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 0000000000..2352d59cfd --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,26 @@ +name: Lint and Format + +on: + pull_request: + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + pre-commit: + runs-on: ubuntu-24.04 + name: ubuntu-24.04-3.12-examples + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' # Update to your project's version + + - name: Run pre-commit hooks + uses: pre-commit/action@v3.0.1 diff --git a/.github/workflows/generic.yml b/.github/workflows/generic.yml index a7640e3e64..34131df5a2 100644 --- a/.github/workflows/generic.yml +++ b/.github/workflows/generic.yml @@ -127,12 +127,6 @@ jobs: pip install --upgrade pip setuptools pkg-info wheel pip3 install torch --index-url https://download.pytorch.org/whl/cpu - - name: Black Format Check - if: ${{ matrix.OS == 'ubuntu-24.04' && matrix.PYTHON_VERSION == '3.12' && matrix.GS_BACKEND == 'cpu' && matrix.GS_ENABLE_NDARRAY == '1' }} - run: | - pip install black - black --line-length 120 --check . - - name: Install Genesis shell: bash run: | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 30c473d7eb..ce8092e6d8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,7 @@ repos: - - repo: https://github.com/psf/black - rev: 25.1.0 - hooks: - - id: black +- repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.14.11 + hooks: + # Run the formatter. + - id: ruff-format diff --git a/examples/IPC_Solver/genesis_ipc_motion_test.py b/examples/IPC_Solver/genesis_ipc_motion_test.py index 665f1151c7..703f176109 100644 --- a/examples/IPC_Solver/genesis_ipc_motion_test.py +++ b/examples/IPC_Solver/genesis_ipc_motion_test.py @@ -223,9 +223,9 @@ def compute_total_linear_momentum(): rigid_v = np.asarray(rigid_v).flatten() fem_v = np.asarray(fem_v).flatten() - print(f"\n{'='*70}") + print(f"\n{'=' * 70}") print(f"Step {i_step:4d}: t = {i_step * dt:.3f}s") - print(f"{'-'*70}") + print(f"{'-' * 70}") print(f"Rigid mass: {rigid_m:8.4f} kg") print(f"Rigid vel: [{rigid_v[0]:9.5f}, {rigid_v[1]:9.5f}, {rigid_v[2]:9.5f}] m/s") print(f"Rigid mom: [{rigid_p[0]:9.5f}, {rigid_p[1]:9.5f}, {rigid_p[2]:9.5f}] kg·m/s") @@ -297,9 +297,9 @@ def compute_total_linear_momentum(): plt.tight_layout() plt.savefig("momentum_conservation_test.png", dpi=150) - print(f"\n{'='*70}") + print(f"\n{'=' * 70}") print("Plot saved to: momentum_conservation_test.png") - print(f"{'='*70}") + print(f"{'=' * 70}") plt.show() diff --git a/examples/IPC_Solver/ipc_twist_cloth_band.py b/examples/IPC_Solver/ipc_twist_cloth_band.py index eb7223ce23..99bc87afd9 100644 --- a/examples/IPC_Solver/ipc_twist_cloth_band.py +++ b/examples/IPC_Solver/ipc_twist_cloth_band.py @@ -228,11 +228,12 @@ def main(): # Progress reporting if frame % 100 == 0: - phase = ( - "Gripping" - if total_t < grip_duration - else "Twisting" if total_t < twist_start_time + twist_duration else "Settling" - ) + if total_t < grip_duration: + phase = "Gripping" + elif total_t < twist_start_time + twist_duration: + phase = "Twisting" + else: + phase = "Settling" print(f" Frame {frame}/{total_frames} (t={total_t:.2f}s) - {phase}") diff --git a/examples/rigid/diffik_controller.py b/examples/rigid/diffik_controller.py index 1f1f5d1d26..84a8d3f9b0 100644 --- a/examples/rigid/diffik_controller.py +++ b/examples/rigid/diffik_controller.py @@ -11,7 +11,6 @@ def main(): - parser = argparse.ArgumentParser() parser.add_argument("-v", "--vis", action="store_true", default=False) parser.add_argument("-c", "--cpu", action="store_true", default=False) diff --git a/examples/rigid/gravity_compensation.py b/examples/rigid/gravity_compensation.py index 6b09822d9b..cb8c938978 100644 --- a/examples/rigid/gravity_compensation.py +++ b/examples/rigid/gravity_compensation.py @@ -4,7 +4,6 @@ def main(): - parser = argparse.ArgumentParser() parser.add_argument("-v", "--vis", action="store_true", default=False) parser.add_argument("-c", "--cpu", action="store_true", default=False) diff --git a/examples/rigid/ik_duck.py b/examples/rigid/ik_duck.py index 513e6e1dcd..7fe6827eeb 100644 --- a/examples/rigid/ik_duck.py +++ b/examples/rigid/ik_duck.py @@ -6,7 +6,6 @@ def main(): - parser = argparse.ArgumentParser() parser.add_argument("-v", "--vis", action="store_true", default=False) args = parser.parse_args() diff --git a/examples/rigid/ik_franka.py b/examples/rigid/ik_franka.py index dc8fa0a9f6..3f1883a089 100644 --- a/examples/rigid/ik_franka.py +++ b/examples/rigid/ik_franka.py @@ -6,7 +6,6 @@ def main(): - parser = argparse.ArgumentParser() parser.add_argument("-v", "--vis", action="store_true", default=False) args = parser.parse_args() diff --git a/examples/rigid/ik_franka_batched.py b/examples/rigid/ik_franka_batched.py index 97d818630d..e756199de3 100644 --- a/examples/rigid/ik_franka_batched.py +++ b/examples/rigid/ik_franka_batched.py @@ -6,7 +6,6 @@ def main(): - parser = argparse.ArgumentParser() parser.add_argument("-v", "--vis", action="store_true", default=False) args = parser.parse_args() diff --git a/examples/rigid/multi_gpu.py b/examples/rigid/multi_gpu.py index d2d1eca33c..cd99568d70 100644 --- a/examples/rigid/multi_gpu.py +++ b/examples/rigid/multi_gpu.py @@ -8,7 +8,6 @@ def main(): - parser = argparse.ArgumentParser() parser.add_argument("-v", "--vis", action="store_true", default=False) args = parser.parse_args() diff --git a/examples/rigid/nonconvex_mesh.py b/examples/rigid/nonconvex_mesh.py index a7018d4e9a..96639378ab 100644 --- a/examples/rigid/nonconvex_mesh.py +++ b/examples/rigid/nonconvex_mesh.py @@ -4,7 +4,6 @@ def main(): - parser = argparse.ArgumentParser() parser.add_argument("-v", "--vis", action="store_true", default=False) parser.add_argument("-c", "--cpu", action="store_true", default=False) diff --git a/examples/rigid/single_franka.py b/examples/rigid/single_franka.py index d24088be12..ef554a380b 100644 --- a/examples/rigid/single_franka.py +++ b/examples/rigid/single_franka.py @@ -4,7 +4,6 @@ def main(): - parser = argparse.ArgumentParser() parser.add_argument("-v", "--vis", action="store_true", default=False) parser.add_argument("-c", "--cpu", action="store_true", default=False) diff --git a/examples/rigid/suction_cup.py b/examples/rigid/suction_cup.py index 2aac74ff78..155a2e634f 100644 --- a/examples/rigid/suction_cup.py +++ b/examples/rigid/suction_cup.py @@ -4,7 +4,6 @@ def main(): - parser = argparse.ArgumentParser() parser.add_argument("-v", "--vis", action="store_true", default=False) parser.add_argument("-c", "--cpu", action="store_true", default=False) diff --git a/examples/rigid/terrain_height_field.py b/examples/rigid/terrain_height_field.py index 5d3c880bf9..0273b28c3e 100644 --- a/examples/rigid/terrain_height_field.py +++ b/examples/rigid/terrain_height_field.py @@ -8,7 +8,6 @@ def main(): - parser = argparse.ArgumentParser() parser.add_argument("-v", "--vis", action="store_true", default=False) parser.add_argument("-c", "--cpu", action="store_true", default=False) diff --git a/examples/smoke.py b/examples/smoke.py index 5762d9625b..0b68fe377d 100644 --- a/examples/smoke.py +++ b/examples/smoke.py @@ -131,7 +131,6 @@ def main(): scene.build() for i in range(args.num_steps): - scalars = scene.sim.solvers[-1].grid.q.to_numpy().astype(np.float32) # (res, res, res, 3) scalars[scalars < 1e-4] = 0 layer = scalars[:, res // 2, :] diff --git a/genesis/__init__.py b/genesis/__init__.py index 57e9229af1..bf749a8005 100644 --- a/genesis/__init__.py +++ b/genesis/__init__.py @@ -108,9 +108,9 @@ def init( wave_width = max(0, min(38, wave_width)) bar_width = wave_width * 2 + 9 wave = ("┈┉" * wave_width)[:wave_width] - logger.info(f"~<╭{'─'*(bar_width)}╮>~") + logger.info(f"~<╭{'─' * (bar_width)}╮>~") logger.info(f"~<│{wave}>~ ~~~~~~~~ ~<{wave}│>~") - logger.info(f"~<╰{'─'*(bar_width)}╯>~") + logger.info(f"~<╰{'─' * (bar_width)}╯>~") # Get concrete device and backend global device diff --git a/genesis/datatypes.py b/genesis/datatypes.py index 0e6f8080a4..0775c7f3fd 100644 --- a/genesis/datatypes.py +++ b/genesis/datatypes.py @@ -46,10 +46,10 @@ def _repr_elem(self, elem, common_length=0): def _repr_elem_colorized(self, elem, common_length=0): content = self._repr_elem(elem, common_length) idx = content.find(">") - formatted_content = f"{colors.BLUE}{formats.ITALIC}{content[:idx + 1]}{formats.RESET}{content[idx + 1:]}" + formatted_content = f"{colors.BLUE}{formats.ITALIC}{content[: idx + 1]}{formats.RESET}{content[idx + 1 :]}" idx = formatted_content.find(":") if idx >= 0: - formatted_content = f"{formatted_content[:idx]}{colors.GRAY}:{colors.MINT}{formatted_content[idx + 1:]}" + formatted_content = f"{formatted_content[:idx]}{colors.GRAY}:{colors.MINT}{formatted_content[idx + 1 :]}" formatted_content += formats.RESET return formatted_content diff --git a/genesis/engine/boundaries/boundaries.py b/genesis/engine/boundaries/boundaries.py index b2f77a7915..2ca8756c0a 100644 --- a/genesis/engine/boundaries/boundaries.py +++ b/genesis/engine/boundaries/boundaries.py @@ -70,4 +70,4 @@ def impose_pos(self, pos): return pos def __repr__(self): - return f"{brief(self)}\n" f"height : {brief(self.height)}\n" f"restitution : {brief(self.restitution)}" + return f"{brief(self)}\nheight : {brief(self.height)}\nrestitution : {brief(self.restitution)}" diff --git a/genesis/engine/couplers/ipc_coupler.py b/genesis/engine/couplers/ipc_coupler.py index 772cc87381..0b17df5447 100644 --- a/genesis/engine/couplers/ipc_coupler.py +++ b/genesis/engine/couplers/ipc_coupler.py @@ -603,7 +603,7 @@ def _scale_genesis_rigid_link_masses(self, link_geoms_dict): rigid_solver.links_info.inertial_i[link_idx] = original_inertia / 2.0 gs.logger.debug( - f" Link {link_idx}: mass {original_mass:.6f} -> {original_mass/2.0:.6f} kg, " f"inertia scaled by 0.5" + f" Link {link_idx}: mass {original_mass:.6f} -> {original_mass / 2.0:.6f} kg, inertia scaled by 0.5" ) # After scaling inertial_mass and inertial_i, we need to recompute derived quantities: diff --git a/genesis/engine/couplers/legacy_coupler.py b/genesis/engine/couplers/legacy_coupler.py index d504b243f4..d8cbf7d775 100644 --- a/genesis/engine/couplers/legacy_coupler.py +++ b/genesis/engine/couplers/legacy_coupler.py @@ -822,7 +822,6 @@ def kernel_pbd_rigid_solve_animate_particles_by_link(self, clamped_inv_dt: ti.f3 pdb = self.pbd_solver for i_p, i_env in ti.ndrange(pdb._n_particles, pdb._B): if self.particle_attach_info[i_p, i_env].link_idx >= 0: - # read link state link_idx = self.particle_attach_info[i_p, i_env].link_idx link_pos = links_state.pos[link_idx, i_env] @@ -940,7 +939,6 @@ def preprocess(self, f): def couple(self, f): # MPM <-> all others if self.mpm_solver.is_active: - self.mpm_grid_op( f, self.sim.cur_t, diff --git a/genesis/engine/couplers/sap_coupler.py b/genesis/engine/couplers/sap_coupler.py index a4cc437686..d28e0be8d8 100644 --- a/genesis/engine/couplers/sap_coupler.py +++ b/genesis/engine/couplers/sap_coupler.py @@ -213,8 +213,7 @@ def __init__( self._rigid_rigid_contact_type = RigidRigidContactType.NONE else: gs.raise_exception( - f"Invalid rigid-rigid contact type: {options.rigid_rigid_contact_type}. " - "Must be one of 'tet' or 'none'." + f"Invalid rigid-rigid contact type: {options.rigid_rigid_contact_type}. Must be one of 'tet' or 'none'." ) self._rigid_compliant = False diff --git a/genesis/engine/sensors/depth_camera.py b/genesis/engine/sensors/depth_camera.py index aba7815668..f5c1987b31 100644 --- a/genesis/engine/sensors/depth_camera.py +++ b/genesis/engine/sensors/depth_camera.py @@ -8,7 +8,6 @@ @register_sensor(DepthCameraOptions, RaycasterSharedMetadata, RaycasterData) class DepthCameraSensor(RaycasterSensor): - def build(self): super().build() batch_shape = (self._manager._sim._B,) if self._manager._sim.n_envs > 0 else () diff --git a/genesis/engine/sensors/raycaster.py b/genesis/engine/sensors/raycaster.py index 03a9a93db2..e112b9998e 100644 --- a/genesis/engine/sensors/raycaster.py +++ b/genesis/engine/sensors/raycaster.py @@ -316,7 +316,6 @@ class RaycasterData(NamedTuple): @register_sensor(RaycasterOptions, RaycasterSharedMetadata, RaycasterData) @ti.data_oriented class RaycasterSensor(RigidSensorMixin, Sensor): - def __init__( self, options: RaycasterOptions, diff --git a/genesis/engine/simulator.py b/genesis/engine/simulator.py index bafdd5cff7..5f70224f87 100644 --- a/genesis/engine/simulator.py +++ b/genesis/engine/simulator.py @@ -283,7 +283,6 @@ def step(self, in_backward=False): def _step_grad(self): for _ in range(self._substeps - 1, -1, -1): - if self.cur_substep_local == 0: self.load_ckpt() self._cur_substep_global -= 1 diff --git a/genesis/engine/solvers/rigid/collider_decomp.py b/genesis/engine/solvers/rigid/collider_decomp.py index 5379f9aaea..89b7cc36f6 100644 --- a/genesis/engine/solvers/rigid/collider_decomp.py +++ b/genesis/engine/solvers/rigid/collider_decomp.py @@ -861,7 +861,6 @@ def func_contact_edge_sdf( for i_e in range(geoms_info.edge_start[i_ga], geoms_info.edge_end[i_ga]): cur_length = edges_info.length[i_e] if cur_length > ga_sdf_cell_size: - i_v0 = edges_info.v0[i_e] i_v1 = edges_info.v1[i_e] @@ -891,10 +890,8 @@ def func_contact_edge_sdf( normal_edge_1 = sdf_grad_1_a - sdf_grad_1_a.dot(vec_01) * vec_01 if normal_edge_0.dot(sdf_grad_0_b) < 0 or normal_edge_1.dot(sdf_grad_1_b) < 0: - # check if closest point is between the two points if sdf_grad_0_b.dot(vec_01) < 0 and sdf_grad_1_b.dot(vec_01) > 0: - while cur_length > ga_sdf_cell_size: p_mid = 0.5 * (p_0 + p_1) if ( diff --git a/genesis/engine/solvers/rigid/constraint_solver_decomp.py b/genesis/engine/solvers/rigid/constraint_solver_decomp.py index dcdef441bc..d0d6953168 100644 --- a/genesis/engine/solvers/rigid/constraint_solver_decomp.py +++ b/genesis/engine/solvers/rigid/constraint_solver_decomp.py @@ -1412,7 +1412,6 @@ def func_ls_init( rigid_global_info: array_class.RigidGlobalInfo, static_rigid_sim_config: ti.template(), ): - n_dofs = constraint_state.search.shape[0] n_entities = entities_info.dof_start.shape[0] # mv and jv diff --git a/genesis/engine/solvers/rigid/constraint_solver_decomp_island.py b/genesis/engine/solvers/rigid/constraint_solver_decomp_island.py index 59ab66bc10..bcda3e2f89 100644 --- a/genesis/engine/solvers/rigid/constraint_solver_decomp_island.py +++ b/genesis/engine/solvers/rigid/constraint_solver_decomp_island.py @@ -238,7 +238,6 @@ def add_collision_constraints_and_wakeup_entities(self, i_island: int, i_b: int) @ti.func def add_joint_limit_constraints(self, i_island: int, i_b: int): for i_island_entity in range(self.contact_island.island_entity[i_island, i_b].n): - i_e_ = self.contact_island.island_entity[i_island, i_b].start + i_island_entity i_e = self.contact_island.entity_id[i_e_, i_b] @@ -448,7 +447,6 @@ def _func_nt_chol_factor(self, island, i_b): for j_d in range( ti.max(i_d + 1, self.entities_info.dof_start[j_e]), self.entities_info.dof_end[j_e] ): - dot = gs.ti_float(0.0) for k_island_entity in range(i_island_entity + 1): @@ -473,7 +471,6 @@ def _func_nt_chol_solve(self, island, i_b): i_e_ = self.contact_island.island_entity[island, i_b].start + i_island_entity i_e = self.contact_island.entity_id[i_e_, i_b] for i_d in range(self.entities_info.dof_start[i_e], self.entities_info.dof_end[i_e]): - for j_island_entity in range(i_island_entity + 1): j_e_ = self.contact_island.island_entity[island, i_b].start + j_island_entity j_e = self.contact_island.entity_id[j_e_, i_b] @@ -715,7 +712,6 @@ def _func_linesearch(self, island, i_b): done = True break if not done: - if self.ls_it[i_b] >= self.ls_iterations: self.ls_result[i_b] = 3 ls_slope = ti.abs(p1_deriv_0) * slopescl @@ -780,7 +776,6 @@ def _func_linesearch(self, island, i_b): res_alpha = self.candidates[4 * best_i + 0, i_b] done = True else: - ( b1, p1_alpha, @@ -816,7 +811,6 @@ def _func_linesearch(self, island, i_b): done = True if not done: - if p1_cost <= p2_cost and p1_cost < p0_cost: self.ls_result[i_b] = 4 ls_slope = ti.abs(p1_deriv_0) * slopescl @@ -958,7 +952,6 @@ def _func_update_constraint(self, island, i_b, qacc, Ma, cost): i_e_ = self.contact_island.island_entity[island, i_b].start + i_island_entity i_e = self.contact_island.entity_id[i_e_, i_b] for i_d in range(self.entities_info.dof_start[i_e], self.entities_info.dof_end[i_e]): - v = ( 0.5 * (Ma[i_d, i_b] - self._solver.dofs_state.force[i_d, i_b]) diff --git a/genesis/engine/solvers/rigid/rigid_solver_decomp.py b/genesis/engine/solvers/rigid/rigid_solver_decomp.py index 53c07e1fb2..c7d66efc67 100644 --- a/genesis/engine/solvers/rigid/rigid_solver_decomp.py +++ b/genesis/engine/solvers/rigid/rigid_solver_decomp.py @@ -2728,8 +2728,7 @@ def update_qacc_from_qvel_delta( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_dofs)) + ti.static(range(static_rigid_sim_config.max_n_awake_dofs)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -2769,8 +2768,7 @@ def update_qvel( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_dofs)) + ti.static(range(static_rigid_sim_config.max_n_awake_dofs)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -3465,8 +3463,7 @@ def func_compute_mass_matrix( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_links)) + ti.static(range(static_rigid_sim_config.max_n_awake_links)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -3501,8 +3498,7 @@ def func_compute_mass_matrix( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_entities)) + ti.static(range(static_rigid_sim_config.max_n_awake_entities)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -3551,8 +3547,7 @@ def func_compute_mass_matrix( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_links)) + ti.static(range(static_rigid_sim_config.max_n_awake_links)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -3598,8 +3593,7 @@ def func_compute_mass_matrix( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_entities)) + ti.static(range(static_rigid_sim_config.max_n_awake_entities)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -3623,8 +3617,7 @@ def func_compute_mass_matrix( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static( + ti.static( # Static inner loop for backward pass ti.ndrange( static_rigid_sim_config.max_n_dofs_per_entity, static_rigid_sim_config.max_n_dofs_per_entity, @@ -4075,8 +4068,7 @@ def func_solve_mass_batch( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_entities)) + ti.static(range(static_rigid_sim_config.max_n_awake_entities)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(static_rigid_sim_config.max_n_links_per_entity)) ) @@ -4409,8 +4401,7 @@ def func_update_cartesian_space_batch( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_entities)) + ti.static(range(static_rigid_sim_config.max_n_awake_entities)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(static_rigid_sim_config.max_n_links_per_entity)) ) @@ -5467,8 +5458,7 @@ def func_update_geoms_entity( # Dynamic inner loop for forward pass range(entities_info.n_geoms[i_e]) if ti.static(not BW) - # Static inner loop for backward pass - else ti.static(range(static_rigid_sim_config.max_n_geoms_per_entity)) + else ti.static(range(static_rigid_sim_config.max_n_geoms_per_entity)) # Static inner loop for backward pass ): i_g = entities_info.geom_start[i_e] + i_g_ if func_check_index_range(i_g, entities_info.geom_start[i_e], entities_info.geom_end[i_e], BW): @@ -5511,8 +5501,7 @@ def func_update_geoms_batch( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_entities)) + ti.static(range(static_rigid_sim_config.max_n_awake_entities)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(static_rigid_sim_config.max_n_links_per_entity)) ) @@ -5760,8 +5749,7 @@ def func_forward_velocity_batch( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_entities)) + ti.static(range(static_rigid_sim_config.max_n_awake_entities)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(static_rigid_sim_config.max_n_links_per_entity)) ) @@ -6347,8 +6335,7 @@ def func_torque_and_passive_force( ) if ti.static(not BW) else ( - # Static inner for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_dofs)) + ti.static(range(static_rigid_sim_config.max_n_awake_dofs)) # Static inner for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -6380,8 +6367,7 @@ def func_torque_and_passive_force( ) if ti.static(not BW) else ( - # Static inner for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_links)) + ti.static(range(static_rigid_sim_config.max_n_awake_links)) # Static inner for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -6457,8 +6443,7 @@ def func_update_acc( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_entities)) + ti.static(range(static_rigid_sim_config.max_n_awake_entities)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -6558,8 +6543,7 @@ def func_update_force( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_links)) + ti.static(range(static_rigid_sim_config.max_n_awake_links)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -6613,8 +6597,7 @@ def func_update_force( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_entities)) + ti.static(range(static_rigid_sim_config.max_n_awake_entities)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -6699,8 +6682,7 @@ def func_bias_force( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_links)) + ti.static(range(static_rigid_sim_config.max_n_awake_links)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -6789,8 +6771,7 @@ def func_compute_qacc( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_entities)) + ti.static(range(static_rigid_sim_config.max_n_awake_entities)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -6840,8 +6821,7 @@ def func_integrate( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_dofs)) + ti.static(range(static_rigid_sim_config.max_n_awake_dofs)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -6874,8 +6854,7 @@ def func_integrate( ) if ti.static(not BW) else ( - # Static inner loop for backward pass - ti.static(range(static_rigid_sim_config.max_n_awake_links)) + ti.static(range(static_rigid_sim_config.max_n_awake_links)) # Static inner loop for backward pass if ti.static(static_rigid_sim_config.use_hibernation) else ti.static(range(1)) ) @@ -7584,7 +7563,6 @@ def kernel_set_links_pos_grad( rigid_global_info: array_class.RigidGlobalInfo, static_rigid_sim_config: ti.template(), ): - ti.loop_config(serialize=static_rigid_sim_config.para_level < gs.PARA_LEVEL.ALL) for i_l_, i_b_ in ti.ndrange(links_idx.shape[0], envs_idx.shape[0]): i_b = envs_idx[i_b_] diff --git a/genesis/engine/solvers/sph_solver.py b/genesis/engine/solvers/sph_solver.py index f4de0d00ce..a6b19f1543 100644 --- a/genesis/engine/solvers/sph_solver.py +++ b/genesis/engine/solvers/sph_solver.py @@ -508,7 +508,6 @@ def _divergence_solve(self, f: ti.i32): iteration = gs.ti_int(0) avg_density_err = gs.ti_float(0.0) while iteration < self._df_max_div_iters: - avg_density_err = self._divergence_solver_iteration() # Max allowed density fluctuation # The SI unit for divergence is s^-1, use max density error divided by time step size diff --git a/genesis/engine/states/cache.py b/genesis/engine/states/cache.py index 65b526ec67..bf01af0bdf 100644 --- a/genesis/engine/states/cache.py +++ b/genesis/engine/states/cache.py @@ -41,4 +41,4 @@ def __getitem__(self, key): return self.states[key] def __repr__(self): - return f"{brief(self)}\n" f"states: {brief(self.states)}" + return f"{brief(self)}\nstates: {brief(self.states)}" diff --git a/genesis/ext/_trimesh_patch.py b/genesis/ext/_trimesh_patch.py index d9e146d72c..311448bd5b 100644 --- a/genesis/ext/_trimesh_patch.py +++ b/genesis/ext/_trimesh_patch.py @@ -139,10 +139,7 @@ def load_obj( # maxsplit=1 means that it can stop working # after it finds the first newline # passed as arg as it's not a kwarg in python2 - face_lines = [ - i.split("\n", 1)[0].strip() - for i in re.split("^f", chunk, flags=re.MULTILINE)[1:] - ] + face_lines = [i.split("\n", 1)[0].strip() for i in re.split("^f", chunk, flags=re.MULTILINE)[1:]] # check every face for mixed tri-quad-ngon columns = len(face_lines[0].replace("/", " ").split()) @@ -152,9 +149,7 @@ def load_obj( if flat_array: # the fastest way to get to a numpy array # processes the whole string at once into a 1D array - array = np.fromstring( - " ".join(face_lines).replace("/", " "), sep=" ", dtype=np.int64 - ) + array = np.fromstring(" ".join(face_lines).replace("/", " "), sep=" ", dtype=np.int64) # also wavefront is 1-indexed (vs 0-indexed) so offset # only applies to positive indices array[array > 0] -= 1 @@ -193,9 +188,7 @@ def load_obj( else: mask_vn = None # no face normals but face texturre - new_faces, mask_v, mask_vt = unmerge_faces( - faces, faces_tex, maintain_faces=maintain_order - ) + new_faces, mask_v, mask_vt = unmerge_faces(faces, faces_tex, maintain_faces=maintain_order) if tol.strict: # we should NOT have messed up the faces @@ -223,9 +216,7 @@ def load_obj( assert faces.max() < len(v) if vn is not None and np.shape(faces_norm) == faces.shape: # do the crazy unmerging logic for split indices - new_faces, mask_v, mask_vn = unmerge_faces( - faces, faces_norm, maintain_faces=maintain_order - ) + new_faces, mask_v, mask_vn = unmerge_faces(faces, faces_norm, maintain_faces=maintain_order) else: # generate the mask so we only include # referenced vertices in every new mesh @@ -255,9 +246,7 @@ def load_obj( normals = vn[mask_vn] if normals.shape != mesh["vertices"].shape: raise ValueError( - "incorrect normals {} != {}".format( - str(normals.shape), str(mesh["vertices"].shape) - ) + "incorrect normals {} != {}".format(str(normals.shape), str(mesh["vertices"].shape)) ) mesh["vertex_normals"] = normals except BaseException: @@ -571,11 +560,7 @@ def _parse_vertices(text): return None, None, None, None # find the last position of each valid value - ends = { - k: text.find("\n", text.rfind(f"\n{k} ") + 2 + len(k)) - for k, v in starts.items() - if v >= 0 - } + ends = {k: text.find("\n", text.rfind(f"\n{k} ") + 2 + len(k)) for k, v in starts.items() if v >= 0} # take the first and last position of any vertex property start = min(s for s in starts.values() if s >= 0) @@ -584,11 +569,7 @@ def _parse_vertices(text): chunk = text[start:end].replace("+e", "e").replace("-e", "e") # get the clean-ish data from the file as python lists - data = { - k: [i.split("\n", 1)[0] for i in chunk.split(f"\n{k} ")[1:]] - for k, v in starts.items() - if v >= 0 - } + data = {k: [i.split("\n", 1)[0] for i in chunk.split(f"\n{k} ")[1:]] for k, v in starts.items() if v >= 0} # count the number of data values per row on a sample row per_row = {k: len(v[0].split()) for k, v in data.items()} @@ -842,29 +823,16 @@ def export_obj( # we are going to reference face_formats with this face_type = ["v"] # OBJ includes vertex color as RGB elements on the same line - if ( - include_color - and current.visual.kind in ["vertex", "face"] - and len(current.visual.vertex_colors) - ): + if include_color and current.visual.kind in ["vertex", "face"] and len(current.visual.vertex_colors): # create a stacked blob with position and color - v_blob = np.column_stack( - (current.vertices, to_float(current.visual.vertex_colors[:, :3])) - ) + v_blob = np.column_stack((current.vertices, to_float(current.visual.vertex_colors[:, :3]))) else: # otherwise just export vertices v_blob = current.vertices # add the first vertex key and convert the array # add the vertices - export = deque( - [ - "v " - + util.array_to_string( - v_blob, col_delim=" ", row_delim="\nv ", digits=digits - ) - ] - ) + export = deque(["v " + util.array_to_string(v_blob, col_delim=" ", row_delim="\nv ", digits=digits)]) # if include_normals is None then # only include if they're already stored @@ -908,9 +876,7 @@ def export_obj( # export the UV coordinates if len(np.shape(getattr(current.visual, "uv", None))) == 2: - converted = util.array_to_string( - current.visual.uv, col_delim=" ", row_delim="\nvt ", digits=digits - ) + converted = util.array_to_string(current.visual.uv, col_delim=" ", row_delim="\nvt ", digits=digits) # if vertex texture exists and is the right shape face_type.append("vt") # add the uv coordinates diff --git a/genesis/ext/isaacgym/terrain_utils.py b/genesis/ext/isaacgym/terrain_utils.py index 7c167903fb..bc99350f3d 100644 --- a/genesis/ext/isaacgym/terrain_utils.py +++ b/genesis/ext/isaacgym/terrain_utils.py @@ -352,7 +352,6 @@ def convert_heightfield_to_trimesh(height_field_raw, horizontal_scale, vertical_ yy, xx = np.meshgrid(y, x) if slope_threshold is not None: - slope_threshold *= horizontal_scale / vertical_scale move_x = np.zeros((num_rows, num_cols)) move_y = np.zeros((num_rows, num_cols)) diff --git a/genesis/ext/pyrender/font.py b/genesis/ext/pyrender/font.py index d0c32f8945..e47a17d192 100644 --- a/genesis/ext/pyrender/font.py +++ b/genesis/ext/pyrender/font.py @@ -79,7 +79,6 @@ def __init__(self, font_file, font_pt=40): self._character_map = {} for i in range(0, 128): - # Generate texture face = self._face face.load_char(chr(i)) diff --git a/genesis/ext/pyrender/interaction/aabb.py b/genesis/ext/pyrender/interaction/aabb.py index b990343898..8f22548f0d 100644 --- a/genesis/ext/pyrender/interaction/aabb.py +++ b/genesis/ext/pyrender/interaction/aabb.py @@ -5,11 +5,12 @@ from .ray import Ray, RayHit, EPSILON from .vec3 import Pose, Vec3 + class AABB: v: "np.typing.NDArray[np.float32]" def __init__(self, v: "np.typing.NDArray[np.float32]"): - assert v.shape == (2, 3,), f"Aabb must be initialized with a (2,3)-element array, got {v.shape}" + assert v.shape == (2, 3), f"Aabb must be initialized with a (2,3)-element array, got {v.shape}" assert v.dtype == np.float32, f"Aabb must be initialized with a float32 array, got {v.dtype}" self.v = v @@ -63,12 +64,12 @@ def __repr__(self) -> str: return f"AABB: Min({self.min.x}, {self.min.y}, {self.min.z}) Max({self.max.x}, {self.max.y}, {self.max.z})" @classmethod - def from_min_max(cls, min: Vec3, max: Vec3) -> 'AABB': + def from_min_max(cls, min: Vec3, max: Vec3) -> "AABB": bounds = np.stack((min.v, max.v), axis=0) return cls(bounds) @classmethod - def from_center_and_half_extents(cls, center: Vec3, half_extents: Vec3) -> 'AABB': + def from_center_and_half_extents(cls, center: Vec3, half_extents: Vec3) -> "AABB": min = center - half_extents max = center + half_extents bounds = np.stack((min.v, max.v), axis=0) diff --git a/genesis/ext/pyrender/interaction/mouse_spring.py b/genesis/ext/pyrender/interaction/mouse_spring.py index f7a692dd15..4c52c6ef23 100644 --- a/genesis/ext/pyrender/interaction/mouse_spring.py +++ b/genesis/ext/pyrender/interaction/mouse_spring.py @@ -49,7 +49,8 @@ def apply_force(self, control_point: Vec3, delta_time: float) -> None: link_T_principal: Pose = Pose(Vec3.from_arraylike(link.inertial_pos), Quat.from_arraylike(link.inertial_quat)) world_T_principal: Pose = link_pose * link_T_principal - arm_in_principal: Vec3 = link_T_principal.inverse_transform_point(self.held_point_in_local) # for non-spherical inertia + # for non-spherical inertia + arm_in_principal: Vec3 = link_T_principal.inverse_transform_point(self.held_point_in_local) arm_in_world: Vec3 = world_T_principal.rot * arm_in_principal # for spherical inertia pos_err_v: Vec3 = control_point - held_point_in_world @@ -63,7 +64,7 @@ def apply_force(self, control_point: Vec3, delta_time: float) -> None: total_impulse: Vec3 = Vec3.zero() total_torque_impulse: Vec3 = Vec3.zero() - for i in range(3*4): + for i in range(3 * 4): body_point_vel: Vec3 = lin_vel + ang_vel.cross(arm_in_world) vel_err_v: Vec3 = Vec3.zero() - body_point_vel @@ -87,8 +88,8 @@ def apply_force(self, control_point: Vec3, delta_time: float) -> None: total_torque = total_torque_impulse * inv_dt force_tensor: torch.Tensor = total_force.as_tensor()[None] torque_tensor: torch.Tensor = total_torque.as_tensor()[None] - link.solver.apply_links_external_force(force_tensor, (link.idx,), ref='link_com', local=False) - link.solver.apply_links_external_torque(torque_tensor, (link.idx,), ref='link_com', local=False) + link.solver.apply_links_external_force(force_tensor, (link.idx,), ref="link_com", local=False) + link.solver.apply_links_external_torque(torque_tensor, (link.idx,), ref="link_com", local=False) @property def is_attached(self) -> bool: diff --git a/genesis/ext/pyrender/interaction/ray.py b/genesis/ext/pyrender/interaction/ray.py index 9d83bce482..b571731ac0 100644 --- a/genesis/ext/pyrender/interaction/ray.py +++ b/genesis/ext/pyrender/interaction/ray.py @@ -39,7 +39,7 @@ def is_hit(self) -> bool: return self.distance < _MAX_RAY_DISTANCE @classmethod - def no_hit(cls) -> 'RayHit': + def no_hit(cls) -> "RayHit": return RayHit(_MAX_RAY_DISTANCE, Vec3.zero(), Vec3.zero(), None) diff --git a/genesis/ext/pyrender/interaction/vec3.py b/genesis/ext/pyrender/interaction/vec3.py index 5f52a53462..7fe61a490e 100644 --- a/genesis/ext/pyrender/interaction/vec3.py +++ b/genesis/ext/pyrender/interaction/vec3.py @@ -17,6 +17,7 @@ class Vec3: This also makes vector dimensionality explicit for linting and static analysis. """ + v: "np.typing.NDArray[np.float32]" def __init__(self, v: "np.typing.NDArray[np.float32]"): @@ -24,28 +25,28 @@ def __init__(self, v: "np.typing.NDArray[np.float32]"): assert v.dtype == np.float32, f"Vec3 must be initialized with a float32 array, got {v.dtype}" self.v = v - def __add__(self, other: 'Vec3') -> 'Vec3': + def __add__(self, other: "Vec3") -> "Vec3": return Vec3(self.v + other.v) - def __sub__(self, other: 'Vec3') -> 'Vec3': + def __sub__(self, other: "Vec3") -> "Vec3": return Vec3(self.v - other.v) - def __mul__(self, other: float) -> 'Vec3': + def __mul__(self, other: float) -> "Vec3": return Vec3(self.v * np.float32(other)) - def __rmul__(self, other: float) -> 'Vec3': + def __rmul__(self, other: float) -> "Vec3": return Vec3(self.v * np.float32(other)) - def __neg__(self) -> 'Vec3': + def __neg__(self) -> "Vec3": return Vec3(-self.v) - def dot(self, other: 'Vec3') -> float: + def dot(self, other: "Vec3") -> float: return np.dot(self.v, other.v).item() - def cross(self, other: 'Vec3') -> 'Vec3': + def cross(self, other: "Vec3") -> "Vec3": return Vec3(np.cross(self.v, other.v)) - def normalized(self) -> 'Vec3': + def normalized(self) -> "Vec3": return Vec3(self.v / (np.linalg.norm(self.v) + 1e-24)) def magnitude(self) -> float: @@ -54,7 +55,7 @@ def magnitude(self) -> float: def sqr_magnitude(self) -> float: return np.dot(self.v, self.v) - def copy(self) -> 'Vec3': + def copy(self) -> "Vec3": return Vec3(self.v.copy()) def __repr__(self) -> str: @@ -76,23 +77,24 @@ def z(self) -> float: return self.v[2] @classmethod - def from_xyz(cls, x: float, y: float, z: float) -> 'Vec3': + def from_xyz(cls, x: float, y: float, z: float) -> "Vec3": return cls(np.array([x, y, z], dtype=np.float32)) @classmethod - def from_array(cls, v: np.ndarray) -> 'Vec3': + def from_array(cls, v: np.ndarray) -> "Vec3": assert v.shape == (3,), f"Vec3 must be initialized with a 3-element array, got {v.shape}" - assert v.dtype == np.int32 or v.dtype == np.int64 or v.dtype == np.float32 or v.dtype == np.float64, \ + assert v.dtype == np.int32 or v.dtype == np.int64 or v.dtype == np.float32 or v.dtype == np.float64, ( f"from_array must be initialized with a array of ints/floats 32/64-bit, got {v.dtype}" + ) return cls.from_xyz(*v) @classmethod - def from_tensor(cls, v: torch.Tensor) -> 'Vec3': + def from_tensor(cls, v: torch.Tensor) -> "Vec3": array: np.ndarray = tensor_to_array(v) return cls.from_array(array) @classmethod - def from_arraylike(cls, v: "np.typing.ArrayLike") -> 'Vec3': + def from_arraylike(cls, v: "np.typing.ArrayLike") -> "Vec3": if isinstance(v, np.ndarray): return cls.from_array(v) elif isinstance(v, torch.Tensor): @@ -102,42 +104,42 @@ def from_arraylike(cls, v: "np.typing.ArrayLike") -> 'Vec3': return cls.from_xyz(*v) assert False - @classmethod - def zero(cls) -> 'Vec3': + def zero(cls) -> "Vec3": return cls(np.array([0, 0, 0], dtype=np.float32)) @classmethod - def one(cls) -> 'Vec3': + def one(cls) -> "Vec3": return cls(np.array([1, 1, 1], dtype=np.float32)) @classmethod - def full(cls, fill_value: float) -> 'Vec3': + def full(cls, fill_value: float) -> "Vec3": return cls(np.full((3,), fill_value, dtype=np.float32)) class Quat: v: "np.typing.NDArray[np.float32]" + def __init__(self, v: "np.typing.NDArray[np.float32]"): assert v.shape == (4,), f"Quat must be initialized with a 4-element array, got {v.shape}" assert v.dtype == np.float32, f"Quat must be initialized with a float32 array, got {v.dtype}" self.v = v - def get_inverse(self) -> 'Quat': + def get_inverse(self) -> "Quat": quat_inv = self.v.copy() quat_inv[1:] *= -1 return Quat(quat_inv) - def __mul__(self, other: Union['Quat', Vec3]) -> Union['Quat', Vec3]: + def __mul__(self, other: Union["Quat", Vec3]) -> Union["Quat", Vec3]: if isinstance(other, Quat): # Quaternion * Quaternion w1, x1, y1, z1 = self.w, self.x, self.y, self.z w2, x2, y2, z2 = other.w, other.x, other.y, other.z return Quat.from_wxyz( - w1*w2 - x1*x2 - y1*y2 - z1*z2, - w1*x2 + x1*w2 + y1*z2 - z1*y2, - w1*y2 - x1*z2 + y1*w2 + z1*x2, - w1*z2 + x1*y2 - y1*x2 + z1*w2 + w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2, + w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2, + w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2, + w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2, ) elif isinstance(other, Vec3): # (other, np.ndarray) and other.shape == (3,): # Quaternion * Vector3 -> rotate vector @@ -147,7 +149,7 @@ def __mul__(self, other: Union['Quat', Vec3]) -> Union['Quat', Vec3]: else: return NotImplemented - def copy(self) -> 'Quat': + def copy(self) -> "Quat": return Quat(self.v.copy()) def __repr__(self) -> str: @@ -173,21 +175,21 @@ def z(self) -> float: return self.v[3] @classmethod - def from_wxyz(cls, w: float, x: float, y: float, z: float) -> 'Quat': + def from_wxyz(cls, w: float, x: float, y: float, z: float) -> "Quat": return cls(np.array([w, x, y, z], dtype=np.float32)) @classmethod - def from_array(cls, v: np.ndarray) -> 'Quat': + def from_array(cls, v: np.ndarray) -> "Quat": assert v.shape == (4,), f"Quat must be initialized with a 4-element array, got {v.shape}" return cls.from_wxyz(*v) @classmethod - def from_tensor(cls, v: torch.Tensor) -> 'Quat': + def from_tensor(cls, v: torch.Tensor) -> "Quat": array: np.ndarray = tensor_to_array(v) return cls.from_array(array) @classmethod - def from_arraylike(cls, v: "np.typing.ArrayLike") -> 'Quat': + def from_arraylike(cls, v: "np.typing.ArrayLike") -> "Quat": if isinstance(v, np.ndarray): return cls.from_array(v) elif isinstance(v, torch.Tensor): @@ -217,7 +219,7 @@ def transform_direction(self, direction: Vec3) -> Vec3: def inverse_transform_direction(self, direction: Vec3) -> Vec3: return self.rot.get_inverse() * direction - def get_inverse(self) -> 'Pose': + def get_inverse(self) -> "Pose": inv_rot = self.rot.get_inverse() # inv_pos = -1.0 * (inv_rot * self.pos) # faster -- avoid repeated quat inversion: @@ -226,7 +228,7 @@ def get_inverse(self) -> 'Pose': inv_pos = Vec3(-inv_pos.v[1:]) return Pose(inv_pos, inv_rot) - def __mul__(self, other: Union['Pose', Vec3]) -> Union['Pose', Vec3]: + def __mul__(self, other: Union["Pose", Vec3]) -> Union["Pose", Vec3]: if isinstance(other, Pose): return Pose(self.pos + self.rot * other.pos, self.rot * other.rot) elif isinstance(other, Vec3): @@ -238,7 +240,7 @@ def __repr__(self) -> str: return f"Pose(pos={self.pos}, rot={self.rot})" @classmethod - def from_geom(cls, geom: 'RigidGeom') -> 'Pose': + def from_geom(cls, geom: "RigidGeom") -> "Pose": assert geom._solver.n_envs == 0, "ViewerInteraction only supports single-env for now" # geom.get_pos() and .get_quat() are squeezed if n_envs == 0 pos = Vec3.from_tensor(geom.get_pos()) @@ -246,7 +248,7 @@ def from_geom(cls, geom: 'RigidGeom') -> 'Pose': return Pose(pos, quat) @classmethod - def from_link(cls, link: 'RigidLink') -> 'Pose': + def from_link(cls, link: "RigidLink") -> "Pose": assert link._solver.n_envs == 0, "ViewerInteraction only supports single-env for now" # geom.get_pos() and .get_quat() are squeezed if n_envs == 0 pos = Vec3.from_tensor(link.get_pos()) @@ -264,21 +266,21 @@ class Color: def tuple(self) -> tuple[float, float, float, float]: return (self.r, self.g, self.b, self.a) - def with_alpha(self, alpha: float) -> 'Color': + def with_alpha(self, alpha: float) -> "Color": return Color(self.r, self.g, self.b, alpha) @classmethod - def red(cls) -> 'Color': + def red(cls) -> "Color": return cls(1.0, 0.0, 0.0, 1.0) @classmethod - def green(cls) -> 'Color': + def green(cls) -> "Color": return cls(0.0, 1.0, 0.0, 1.0) @classmethod - def blue(cls) -> 'Color': + def blue(cls) -> "Color": return cls(0.0, 0.0, 1.0, 1.0) @classmethod - def yellow(cls) -> 'Color': + def yellow(cls) -> "Color": return cls(1.0, 1.0, 0.0, 1.0) diff --git a/genesis/ext/pyrender/interaction/viewer_interaction.py b/genesis/ext/pyrender/interaction/viewer_interaction.py index 46d24244d1..b654e61d81 100644 --- a/genesis/ext/pyrender/interaction/viewer_interaction.py +++ b/genesis/ext/pyrender/interaction/viewer_interaction.py @@ -24,17 +24,18 @@ class ViewerInteraction(ViewerInteractionBase): - mouse dragging """ - def __init__(self, - camera: 'Node', - scene: 'Scene', + def __init__( + self, + camera: "Node", + scene: "Scene", viewport_size: tuple[int, int], camera_yfov: float, log_events: bool = False, camera_fov: float = 60.0, ) -> None: super().__init__(log_events) - self.camera: 'Node' = camera - self.scene: 'Scene' = scene + self.camera: "Node" = camera + self.scene: "Scene" = scene self.viewport_size: tuple[int, int] = viewport_size self.camera_yfov: float = camera_yfov @@ -66,7 +67,7 @@ def on_mouse_drag(self, x: int, y: int, dx: int, dy: int, buttons: int, modifier @override def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> EVENT_HANDLE_STATE: super().on_mouse_press(x, y, button, modifiers) - if button == 1: # left mouse button + if button == 1: # left mouse button ray_hit = self.raycast_against_entities(self.screen_position_to_ray(x, y)) with self.lock: if ray_hit.geom: @@ -87,7 +88,7 @@ def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> EVENT_H @override def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> EVENT_HANDLE_STATE: super().on_mouse_release(x, y, button, modifiers) - if button == 1: # left mouse button + if button == 1: # left mouse button with self.lock: self.picked_link = None self.picked_point_in_local = None @@ -119,7 +120,7 @@ def update_on_sim_step(self) -> None: # apply force self.mouse_spring.apply_force(new_mouse_3d_pos, self.scene.sim.dt) else: - #apply displacement + # apply displacement pos = Vec3.from_tensor(self.picked_link.entity.get_pos()) pos += delta_3d_pos self.picked_link.entity.set_pos(pos.as_tensor()) @@ -156,7 +157,6 @@ def on_draw(self) -> None: if closest_hit.geom: self._draw_entity_unrotated_obb(closest_hit.geom) - def screen_position_to_ray(self, x: float, y: float) -> Ray: # convert screen position to ray if True: @@ -234,17 +234,20 @@ def _get_box_obb(self, box_entity: "RigidEntity") -> OBB: half_extents = 0.5 * Vec3.from_xyz(*box.size) return OBB(pose, half_extents) - def _get_geom_placeholder_obb(self, geom: 'RigidGeom') -> OBB: + def _get_geom_placeholder_obb(self, geom: "RigidGeom") -> OBB: pose = Pose.from_geom(geom) half_extents = Vec3.full(0.5 * 0.125) return OBB(pose, half_extents) def _draw_arrow( - self, pos: Vec3, dir: Vec3, color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0), + self, + pos: Vec3, + dir: Vec3, + color: tuple[float, float, float, float] = (1.0, 1.0, 1.0, 1.0), ) -> None: self.scene.draw_debug_arrow(pos.v, dir.v, color=color) - def _draw_entity_unrotated_obb(self, geom: 'RigidGeom') -> None: + def _draw_entity_unrotated_obb(self, geom: "RigidGeom") -> None: obb: OBB | None = None if isinstance(geom.entity.morph, gs.morphs.Box): obb = self._get_box_obb(geom.entity) diff --git a/genesis/ext/pyrender/interaction/viewer_interaction_base.py b/genesis/ext/pyrender/interaction/viewer_interaction_base.py index ede759dc0c..9be9f545f2 100644 --- a/genesis/ext/pyrender/interaction/viewer_interaction_base.py +++ b/genesis/ext/pyrender/interaction/viewer_interaction_base.py @@ -8,9 +8,9 @@ # Note: Viewer window is based on pyglet.window.Window, mouse events are defined in pyglet.window.BaseWindow -class ViewerInteractionBase(): - """Base class for handling pyglet.window.Window events. - """ + +class ViewerInteractionBase: + """Base class for handling pyglet.window.Window events.""" log_events: bool diff --git a/genesis/ext/pyrender/light.py b/genesis/ext/pyrender/light.py index 65432c7ffa..35c27c4b07 100644 --- a/genesis/ext/pyrender/light.py +++ b/genesis/ext/pyrender/light.py @@ -33,7 +33,6 @@ class Light(metaclass=ABCMeta): """ def __init__(self, color=None, intensity=None, name=None): - if color is None: color = np.ones(3) if intensity is None: diff --git a/genesis/ext/pyrender/material.py b/genesis/ext/pyrender/material.py index dc5573b333..88a92641a0 100644 --- a/genesis/ext/pyrender/material.py +++ b/genesis/ext/pyrender/material.py @@ -89,7 +89,6 @@ def __init__( smooth=True, wireframe=False, ): - # Set defaults if alphaMode is None: alphaMode = "OPAQUE" diff --git a/genesis/ext/pyrender/offscreen.py b/genesis/ext/pyrender/offscreen.py index b0418710c3..1673d0f119 100644 --- a/genesis/ext/pyrender/offscreen.py +++ b/genesis/ext/pyrender/offscreen.py @@ -195,6 +195,7 @@ def render( retval = () if normal: + class CustomShaderCache: def __init__(self): self.program = None diff --git a/genesis/ext/pyrender/primitive.py b/genesis/ext/pyrender/primitive.py index c0408865dc..f715cc4315 100644 --- a/genesis/ext/pyrender/primitive.py +++ b/genesis/ext/pyrender/primitive.py @@ -22,6 +22,7 @@ def _compute_bounds(positions): bounds[1, i] = np.max(positions[:, i]) return bounds + class Primitive(object): """A primitive object which can be rendered. @@ -272,7 +273,7 @@ def poses(self, value): if value.ndim == 2: value = value[np.newaxis, :, :] if value.shape[1] != 4 or value.shape[2] != 4: - raise ValueError("Pose matrices must be of shape (n,4,4), " "got {}".format(value.shape)) + raise ValueError("Pose matrices must be of shape (n,4,4), got {}".format(value.shape)) self._poses = value self._bounds = None @@ -498,7 +499,7 @@ def _in_context(self): def _bind(self): if self._vaid is None: - raise ValueError("Cannot bind a Mesh that has not been added " "to a context") + raise ValueError("Cannot bind a Mesh that has not been added to a context") glBindVertexArray(self._vaid) def _unbind(self): diff --git a/genesis/ext/pyrender/shader_program.py b/genesis/ext/pyrender/shader_program.py index d3742a68ce..8eae1babac 100644 --- a/genesis/ext/pyrender/shader_program.py +++ b/genesis/ext/pyrender/shader_program.py @@ -1,4 +1,5 @@ """OpenGL shader program wrapper.""" + import numbers import os import re @@ -91,7 +92,6 @@ class ShaderProgram(object): """ def __init__(self, vertex_shader, fragment_shader, geometry_shader=None, defines=None): - self.vertex_shader = vertex_shader self.fragment_shader = fragment_shader self.geometry_shader = geometry_shader diff --git a/genesis/ext/pyrender/trackball.py b/genesis/ext/pyrender/trackball.py index 38914e39e2..99f1053f2e 100644 --- a/genesis/ext/pyrender/trackball.py +++ b/genesis/ext/pyrender/trackball.py @@ -113,7 +113,9 @@ def drag(self, point): if self._state == Trackball.STATE_ROTATE: # Compute updated azimut directly. No fancy math here because this angle can controlled freely. roll_angle = np.arctan2(self._pose[2, 1], self._pose[2, 2]) - world_up_axis = np.array([0.0, 0.0, -1.0 if roll_angle < 0.0 else 1.0]) # safeguard for degenerate case when roll_angle = 0 + + # safeguard for degenerate case when roll_angle = 0 + world_up_axis = np.array([0.0, 0.0, -1.0 if roll_angle < 0.0 else 1.0]) azimuth_angle = -dx / mindim azimuth_transform = transformations.rotation_matrix(azimuth_angle, world_up_axis, target) @@ -131,8 +133,8 @@ def drag(self, point): # Compute the elevation axis norm_view_dir = np.linalg.norm(view_dir) if norm_view_dir < EPSILON: - elevation_axis = pose_after_azimuth[:3, 0] - delta_elevation_angle = 0.0 + elevation_axis = pose_after_azimuth[:3, 0] + delta_elevation_angle = 0.0 else: view_dir_normalized = view_dir / norm_view_dir elevation_axis = np.cross(world_up_axis, view_dir_normalized) diff --git a/genesis/ext/pyrender/viewer.py b/genesis/ext/pyrender/viewer.py index 569273f614..c12532bb71 100644 --- a/genesis/ext/pyrender/viewer.py +++ b/genesis/ext/pyrender/viewer.py @@ -688,7 +688,7 @@ def _event_loop_step_offscreen(self): if self._offscreen_pending_close is not None: # Extract request right away - target, = self._offscreen_pending_close + (target,) = self._offscreen_pending_close self._offscreen_pending_close = None # Delete renderer. @@ -1199,6 +1199,7 @@ def _render(self, camera_node=None, renderer=None, normal=False): retval = () if normal: + class CustomShaderCache: def __init__(self): self.program = None @@ -1231,8 +1232,10 @@ def get_program(self, vertex_shader, fragment_shader, geometry_shader=None, defi def start(self, auto_refresh=True): import pyglet # For some reason, this is necessary if 'pyglet.window.xlib' fails to import... + try: import pyglet.window.xlib, pyglet.display.xlib + xlib_exceptions = (pyglet.window.xlib.XlibException, pyglet.display.xlib.NoSuchDisplayException) except ImportError: xlib_exceptions = () @@ -1262,7 +1265,7 @@ def start(self, auto_refresh=True): # of nearest neighbors, and there is no way to tweak this behavior. confs = [ pyglet.gl.Config( - sample_buffers=1, # Enable multi-sampling (MSAA) + sample_buffers=1, # Enable multi-sampling (MSAA) samples=2, depth_size=24, double_buffer=True, diff --git a/genesis/ext/urdfpy/urdf.py b/genesis/ext/urdfpy/urdf.py index d67566ccc4..d432ea46fd 100644 --- a/genesis/ext/urdfpy/urdf.py +++ b/genesis/ext/urdfpy/urdf.py @@ -89,7 +89,7 @@ def _parse_simple_attribs(cls, node): v = cls._parse_attrib(t, node.attrib[a]) except Exception: raise ValueError( - "Missing required attribute {} when parsing an object " "of type {}".format(a, cls.__name__) + "Missing required attribute {} when parsing an object of type {}".format(a, cls.__name__) ) else: v = None @@ -132,8 +132,9 @@ def _parse_simple_elements(cls, node, root, path): vs = node.findall(t._TAG) if len(vs) == 0 and r: raise ValueError( - "Missing required subelement(s) of type {} when " - "parsing an object of type {}".format(t.__name__, cls.__name__) + "Missing required subelement(s) of type {} when parsing an object of type {}".format( + t.__name__, cls.__name__ + ) ) v = [t._from_xml(n, node, path) for n in vs] kwargs[a] = v @@ -641,7 +642,7 @@ def meshes(self, value): raise ValueError("Mesh must have at least one trimesh.Trimesh") for m in value: if not isinstance(m, trimesh.Trimesh): - raise TypeError("Mesh requires a trimesh.Trimesh or a " "list of them") + raise TypeError("Mesh requires a trimesh.Trimesh or a list of them") elif isinstance(value, trimesh.Trimesh): value = [value] else: @@ -901,7 +902,7 @@ def image(self, value): if isinstance(value, np.ndarray): value = PIL.Image.fromarray(value) elif not isinstance(value, PIL.Image.Image): - raise ValueError("Texture only supports numpy arrays " "or PIL images") + raise ValueError("Texture only supports numpy arrays or PIL images") self._image = value @classmethod @@ -997,7 +998,7 @@ def texture(self, value): image = PIL.Image.open(value) value = Texture(filename=value, image=image) elif not isinstance(value, Texture): - raise ValueError("Invalid type for texture -- expect path to " "image or Texture") + raise ValueError("Invalid type for texture -- expect path to image or Texture") self._texture = value @classmethod @@ -2236,7 +2237,7 @@ def limit(self): def limit(self, value): if value is None: if self.joint_type in ["prismatic", "revolute"]: - raise ValueError("Require joint limit for prismatic and " "revolute joints") + raise ValueError("Require joint limit for prismatic and revolute joints") elif not isinstance(value, JointLimit): raise TypeError("Expected JointLimit type") self._limit = value @@ -2741,17 +2742,17 @@ def __init__(self, name, links, joints=None, transmissions=None, materials=None, for x in self._joints: if x.name in self._joint_map: - raise ValueError("Two joints with name {} " "found".format(x.name)) + raise ValueError("Two joints with name {} found".format(x.name)) self._joint_map[x.name] = x for x in self._transmissions: if x.name in self._transmission_map: - raise ValueError("Two transmissions with name {} " "found".format(x.name)) + raise ValueError("Two transmissions with name {} found".format(x.name)) self._transmission_map[x.name] = x for x in self._materials: if x.name in self._material_map: - raise ValueError("Two materials with name {} " "found".format(x.name)) + raise ValueError("Two materials with name {} found".format(x.name)) self._material_map[x.name] = x # Synchronize materials between links and top-level set @@ -3808,7 +3809,7 @@ def _validate_transmissions(self): for t in self.transmissions: for joint in t.joints: if joint.name not in self._joint_map: - raise ValueError("Transmission {} has invalid joint name " "{}".format(t.name, joint.name)) + raise ValueError("Transmission {} has invalid joint name {}".format(t.name, joint.name)) def _validate_graph(self): """Raise an exception if the link-joint structure is invalid. @@ -3835,7 +3836,7 @@ def _validate_graph(self): for n in cc: cluster.append(n.name) link_clusters.append(cluster) - message = "Links are not all connected. " "Connected components are:" + message = "Links are not all connected. Connected components are:" for lc in link_clusters: message += "\n\t" for n in lc: @@ -3874,7 +3875,7 @@ def _process_cfg(self, cfg): joint_cfg[joint] = cfg[joint] elif isinstance(cfg, (list, tuple, np.ndarray)): if len(cfg) != len(self.actuated_joints): - raise ValueError("Cfg must have same length as actuated joints " "if specified as a numerical array") + raise ValueError("Cfg must have same length as actuated joints if specified as a numerical array") for joint, value in zip(self.actuated_joints, cfg): joint_cfg[joint] = value else: diff --git a/genesis/ext/urdfpy/utils.py b/genesis/ext/urdfpy/utils.py index 4f870299e5..597320bc76 100644 --- a/genesis/ext/urdfpy/utils.py +++ b/genesis/ext/urdfpy/utils.py @@ -294,7 +294,7 @@ def configure_origin(value): if value.shape == (6,): value = xyz_rpy_to_matrix(value) elif value.shape != (4, 4): - raise ValueError("Origin must be specified as a 4x4 " "homogenous transformation matrix") + raise ValueError("Origin must be specified as a 4x4 homogenous transformation matrix") else: raise TypeError("Invalid type for origin, expect 4x4 matrix") return value diff --git a/genesis/grad/creation_ops.py b/genesis/grad/creation_ops.py index 27031e77b6..853a82c548 100644 --- a/genesis/grad/creation_ops.py +++ b/genesis/grad/creation_ops.py @@ -54,9 +54,7 @@ def _wrapper(*args, dtype=None, requires_grad=False, scene=None, **kwargs): return from_torch(torch_tensor, dtype, requires_grad, detach=True, scene=scene) _wrapper.__doc__ = ( - f"This method is the genesis wrapper of `torch.{torch_op.__name__}`.\n\n" - "------------------\n" - f"{_wrapper.__doc__}" + f"This method is the genesis wrapper of `torch.{torch_op.__name__}`.\n\n------------------\n{_wrapper.__doc__}" ) return _wrapper diff --git a/genesis/options/options.py b/genesis/options/options.py index 4c4754990e..d7cf3027df 100644 --- a/genesis/options/options.py +++ b/genesis/options/options.py @@ -59,7 +59,7 @@ def __colorized__repr__(self) -> str: content = ru.brief(getattr(self, attr)) idx = content.find(">") - formatted_content = f"{colors.MINT}{formats.ITALIC}{content[:idx + 1]}{formats.RESET}{colors.MINT}{content[idx + 1:]}{formats.RESET}" + formatted_content = f"{colors.MINT}{formats.ITALIC}{content[: idx + 1]}{formats.RESET}{colors.MINT}{content[idx + 1 :]}{formats.RESET}" # in case it's multi-line formatted_content = formatted_content.replace("\n", "\n" + " " * (max_attr_len + 4)) diff --git a/genesis/options/surfaces.py b/genesis/options/surfaces.py index 1fd7412a19..2bc2af0e43 100644 --- a/genesis/options/surfaces.py +++ b/genesis/options/surfaces.py @@ -108,7 +108,7 @@ class Surface(Options): @staticmethod def shortcut_info(name, map_name): - return f"`{name}` is a shortcut for texture. " f"When {name} is set, {map_name} setting is not allowed." + return f"`{name}` is a shortcut for texture. When {name} is set, {map_name} setting is not allowed." def __init__(self, **data): super().__init__(**data) diff --git a/genesis/options/vis.py b/genesis/options/vis.py index fce8ed0d22..017bac65df 100644 --- a/genesis/options/vis.py +++ b/genesis/options/vis.py @@ -120,12 +120,10 @@ class VisOptions(Options): segmentation_level: str = "link" # ['entity', 'link', 'geom'] render_particle_as: str = "sphere" # ['sphere', 'tet'] particle_size_scale: float = 1.0 # scale applied to actual particle size for rendering - contact_force_scale: float = ( - 0.01 # scale of force visualization, m/N. E.g. the force arrow representing 10N wille be 0.1m long if scale is 0.01. - ) - n_support_neighbors: int = ( - 12 # number of neighbor particles used to compute vertex position of the visual mesh. Used for rendering deformable bodies. - ) + # scale of force visualization, m/N. E.g. the force arrow representing 10N wille be 0.1m long if scale is 0.01. + contact_force_scale: float = 0.01 + # number of neighbor particles used to compute vertex position of the visual mesh. Used for rendering deformable bodies. + n_support_neighbors: int = 12 n_rendered_envs: Optional[int] = None # number of environments being rendered rendered_envs_idx: Optional[list] = None # idx of environments being rendered lights: list = [ diff --git a/genesis/recorders/plotters.py b/genesis/recorders/plotters.py index 2443a23eac..731ed8e372 100644 --- a/genesis/recorders/plotters.py +++ b/genesis/recorders/plotters.py @@ -55,7 +55,6 @@ def _data_to_array(data: Sequence) -> np.ndarray: class BasePlotter(Recorder): - def __init__(self, manager: "RecorderManager", options: BasePlotterOptions, data_func: Callable[[], T]): if options.show_window is None: options.show_window = has_display() @@ -138,19 +137,19 @@ def __init__(self, options: LinePlotterMixinOptions, data: dict[str, Sequence] | self._is_dict_data = True if options.labels is not None: - assert isinstance( - options.labels, dict - ), f"[{type(self).__name__}] Labels must be a dict when data is a dict" - assert set(options.labels.keys()) == set( - data.keys() - ), f"[{type(self).__name__}] Label keys must match data keys" + assert isinstance(options.labels, dict), ( + f"[{type(self).__name__}] Labels must be a dict when data is a dict" + ) + assert set(options.labels.keys()) == set(data.keys()), ( + f"[{type(self).__name__}] Label keys must match data keys" + ) for key in data.keys(): data_values = _data_to_array(data[key]) label_values = options.labels[key] - assert len(label_values) == len( - data_values - ), f"[{type(self).__name__}] Label count must match data count for key '{key}'" + assert len(label_values) == len(data_values), ( + f"[{type(self).__name__}] Label count must match data count for key '{key}'" + ) self._subplot_structure[key] = tuple(label_values) else: self._subplot_structure = {} @@ -296,7 +295,6 @@ def get_image_array(self): @register_recording(PyQtLinePlotterOptions) class PyQtLinePlotter(BasePyQtPlotter): - def build(self): super().build() @@ -452,7 +450,6 @@ def run_in_thread(self) -> bool: @register_recording(MPLLinePlotterOptions) class MPLLinePlotter(BaseMPLPlotter): - def build(self): super().build() diff --git a/genesis/repr_base.py b/genesis/repr_base.py index 9d93626986..9efe0fc802 100644 --- a/genesis/repr_base.py +++ b/genesis/repr_base.py @@ -68,7 +68,7 @@ def __colorized__repr__(self) -> str: continue idx = content.find(">") # format with italic and color - formatted_content = f"{colors.MINT}{formats.ITALIC}{content[:idx + 1]}{formats.RESET}{colors.MINT}{content[idx + 1:]}{formats.RESET}" + formatted_content = f"{colors.MINT}{formats.ITALIC}{content[: idx + 1]}{formats.RESET}{colors.MINT}{content[idx + 1 :]}{formats.RESET}" # in case it's multi-line if isinstance(getattr(self, attr), gs.List): # 4 = 2 x ' + : + space diff --git a/genesis/utils/hybrid.py b/genesis/utils/hybrid.py index 70c5db59bd..8058f6a954 100644 --- a/genesis/utils/hybrid.py +++ b/genesis/utils/hybrid.py @@ -53,7 +53,7 @@ def skeletonization(mesh, sampling=True, verbose=False): graph.save(gel_file_path, graph_gel) if verbose: toc = time.time() - print(f"Skeletonization time {toc-tic}") + print(f"Skeletonization time {toc - tic}") return graph_gel diff --git a/genesis/utils/tools.py b/genesis/utils/tools.py index 748fb887e6..880d8a5ca0 100644 --- a/genesis/utils/tools.py +++ b/genesis/utils/tools.py @@ -26,7 +26,7 @@ def animate(imgs, filename=None, fps=60): if filename is None: caller_file = inspect.stack()[-1].filename # caller file + timestamp + .mp4 - filename = os.path.splitext(os.path.basename(caller_file))[0] + f'_{time.strftime("%Y%m%d_%H%M%S")}.mp4' + filename = os.path.splitext(os.path.basename(caller_file))[0] + f"_{time.strftime('%Y%m%d_%H%M%S')}.mp4" os.makedirs(os.path.abspath(os.path.dirname(filename)), exist_ok=True) gs.logger.info(f'Saving video to ~<"{filename}">~...') @@ -102,7 +102,7 @@ def _stamp(self, msg="", _ratio=1.0): prefix = "" print( - f"{prefix}[{msg.ljust(self.msg_width)}] step: {step_time:5.3f}ms | accu: {accu_time:5.3f}ms | step_avg: {self.accu_log[msg][1]/self.accu_log[msg][0]:5.3f}ms | accu_avg: {self.accu_log[msg][2]/self.accu_log[msg][0]:5.3f}ms" + f"{prefix}[{msg.ljust(self.msg_width)}] step: {step_time:5.3f}ms | accu: {accu_time:5.3f}ms | step_avg: {self.accu_log[msg][1] / self.accu_log[msg][0]:5.3f}ms | accu_avg: {self.accu_log[msg][2] / self.accu_log[msg][0]:5.3f}ms" ) self.prev_time = time.perf_counter() @@ -138,7 +138,7 @@ def stamp(self, msg="", _ratio=1.0): prefix = "" print( - f"{prefix}[{msg.ljust(self.msg_width)}] step: {step_time:5.3f}ms | accu: {accu_time:5.3f}ms | step_avg: {self.accu_log[msg][1]/self.accu_log[msg][0]:5.3f}ms | accu_avg: {self.accu_log[msg][2]/self.accu_log[msg][0]:5.3f}ms" + f"{prefix}[{msg.ljust(self.msg_width)}] step: {step_time:5.3f}ms | accu: {accu_time:5.3f}ms | step_avg: {self.accu_log[msg][1] / self.accu_log[msg][0]:5.3f}ms | accu_avg: {self.accu_log[msg][2] / self.accu_log[msg][0]:5.3f}ms" ) self.prev_time = time.perf_counter() diff --git a/genesis/vis/camera.py b/genesis/vis/camera.py index 32cedefa33..54d2484d6d 100644 --- a/genesis/vis/camera.py +++ b/genesis/vis/camera.py @@ -732,7 +732,7 @@ def stop_recording(self, save_to_filename=None, fps=60): caller_file = inspect.stack()[-1].filename save_to_filename = ( os.path.splitext(os.path.basename(caller_file))[0] - + f'_cam_{self.idx}_{time.strftime("%Y%m%d_%H%M%S")}.mp4' + + f"_cam_{self.idx}_{time.strftime('%Y%m%d_%H%M%S')}.mp4" ) if self._is_batched: diff --git a/pyproject.toml b/pyproject.toml index a0dc25dd09..4c65e45112 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -139,7 +139,6 @@ force-exclude = ''' )/ ''' - [tool.ruff] line-length = 120 diff --git a/tests/run_benchmarks.py b/tests/run_benchmarks.py index c4d4ec2b45..3f90cc8de8 100644 --- a/tests/run_benchmarks.py +++ b/tests/run_benchmarks.py @@ -41,7 +41,7 @@ os.chmod(fd.name, 0o755) # Make the script executable for i, commit in enumerate(commits): - print(f"\n[{i+1}/{len(commits)}] Checking out {commit}") + print(f"\n[{i + 1}/{len(commits)}] Checking out {commit}") subprocess.run(["git", "checkout", "-f", commit], check=True) print("================= ...Running benchmarks... ==================") diff --git a/tests/test_bvh.py b/tests/test_bvh.py index cc38fbeda2..9cce6cb957 100644 --- a/tests/test_bvh.py +++ b/tests/test_bvh.py @@ -31,9 +31,9 @@ def test_morton_code(lbvh): # Check that the morton codes are sorted for i_b in range(morton_codes.shape[0]): for i in range(1, morton_codes.shape[1]): - assert ( - morton_codes[i_b, i, 0] > morton_codes[i_b, i - 1, 0] - ), f"Morton codes are not sorted: {morton_codes[i_b, i]} < {morton_codes[i_b, i - 1]}" + assert morton_codes[i_b, i, 0] > morton_codes[i_b, i - 1, 0], ( + f"Morton codes are not sorted: {morton_codes[i_b, i]} < {morton_codes[i_b, i - 1]}" + ) @pytest.mark.required @@ -66,9 +66,9 @@ def expand_bits(lbvh: ti.template(), x: ti.template(), expanded_x: ti.template() str_x = f"{x_np[i]:010b}" str_expanded_x = f"{expanded_x_np[i]:030b}" # check that the expanded bits are correct - assert str_expanded_x == "".join( - f"00{bit}" for bit in str_x - ), f"Expected {str_expanded_x}, got {''.join(f'00{bit}' for bit in str_x)}" + assert str_expanded_x == "".join(f"00{bit}" for bit in str_x), ( + f"Expected {str_expanded_x}, got {''.join(f'00{bit}' for bit in str_x)}" + ) @pytest.mark.required @@ -91,19 +91,19 @@ def test_build_tree(lbvh): assert parent == -1 else: - assert ( - nodes["left"][j, parent] == i or nodes["right"][j, parent] == i - ), f"Node {i} in batch {j} has incorrect parent: {parent}" + assert nodes["left"][j, parent] == i or nodes["right"][j, parent] == i, ( + f"Node {i} in batch {j} has incorrect parent: {parent}" + ) # Check that left and right children are correct if left != -1: - assert ( - nodes["parent"][j, left] == i - ), f"Left child {left} of node {i} in batch {j} has incorrect parent: {nodes['parent'][j, left]}, expected {i}" + assert nodes["parent"][j, left] == i, ( + f"Left child {left} of node {i} in batch {j} has incorrect parent: {nodes['parent'][j, left]}, expected {i}" + ) if right != -1: - assert ( - nodes["parent"][j, right] == i - ), f"Right child {right} of node {i} in batch {j} has incorrect parent: {nodes['parent'][j, right]}, expected {i}" + assert nodes["parent"][j, right] == i, ( + f"Right child {right} of node {i} in batch {j} has incorrect parent: {nodes['parent'][j, right]}, expected {i}" + ) if left != -1 and right != -1: # Check that the AABBs of the children are within the AABB of the parent @@ -155,6 +155,6 @@ def query_kernel(lbvh: ti.template(), aabbs: ti.template()): if i_a == j_a: assert intersect[i_b, i_a, j_a] == True, f"AABB {i_a} should intersect with itself" else: - assert ( - intersect[i_b, i_a, j_a] == intersect[i_b, j_a, i_a] - ), f"AABBs {i_a} and {j_a} should have the same intersection result" + assert intersect[i_b, i_a, j_a] == intersect[i_b, j_a, i_a], ( + f"AABBs {i_a} and {j_a} should have the same intersection result" + ) diff --git a/tests/test_fem.py b/tests/test_fem.py index 0295a02ab7..e733db65c8 100644 --- a/tests/test_fem.py +++ b/tests/test_fem.py @@ -85,9 +85,9 @@ def _point_on_surface(p, verts, faces, tol=1e-6): for idx in surface_indices: p = vertices[idx] - assert _point_on_surface( - p, verts, faces - ), f"Surface vertex index {idx} with coordinate {p} does not lie on any original face" + assert _point_on_surface(p, verts, faces), ( + f"Surface vertex index {idx} with coordinate {p} does not lie on any original face" + ) # Verify whether surface faces in the visualizer mesh matches the surface faces of the FEM entity static_nodes = scene.visualizer.context.static_nodes diff --git a/tests/test_mesh.py b/tests/test_mesh.py index 0d691aa2f4..0ea9fe5136 100644 --- a/tests/test_mesh.py +++ b/tests/test_mesh.py @@ -147,9 +147,9 @@ def check_gs_textures(gs_texture1, gs_texture2, default_value, material_name, te err_msg=f"Texture mismatch for material {material_name} in {texture_name}.", ) else: - assert ( - gs_texture1 is None and gs_texture2 is None - ), f"Both textures should be None for material {material_name} in {texture_name}." + assert gs_texture1 is None and gs_texture2 is None, ( + f"Both textures should be None for material {material_name} in {texture_name}." + ) @pytest.mark.required diff --git a/tests/test_rigid_physics.py b/tests/test_rigid_physics.py index 23bb19d660..da2af310cc 100644 --- a/tests/test_rigid_physics.py +++ b/tests/test_rigid_physics.py @@ -832,10 +832,10 @@ def test_double_pendulum_links_acc(gs_sim, tol): acc_classical_lin_world = tensor_to_array(gs_sim.rigid_solver.get_links_acc()[[0, 2, 4]]) assert_allclose(acc_classical_lin_world[0], 0, tol=tol) acc_classical_lin_local = np.matmul(np.moveaxis(R, 2, 0), acc_classical_lin_world[1:, :, None])[..., 0] - assert_allclose(acc_classical_lin_local[0], np.array([0.0, -theta_ddot[0], -theta_dot[0] ** 2]), tol=tol) + assert_allclose(acc_classical_lin_local[0], np.array([0.0, -theta_ddot[0], -(theta_dot[0] ** 2)]), tol=tol) assert_allclose( acc_classical_lin_local[1], - R[..., 1] @ acc_classical_lin_world[1] + np.array([0.0, -theta_ddot.sum(), -theta_dot.sum() ** 2]), + R[..., 1] @ acc_classical_lin_world[1] + np.array([0.0, -theta_ddot.sum(), -(theta_dot.sum() ** 2)]), tol=tol, )