From 9e6576da44e157b50cec079ce5d847e2bab8a3f3 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 15:49:46 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20[performance=20improvement]?= =?UTF-8?q?=20Replace=20exception-handling=20in=20spatial=20loops=20with?= =?UTF-8?q?=20bound=20checks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced computationally expensive `try...except` blocks with explicit boundary checks (e.g., `0 <= x < 500`) for SWIG array lookups in tightly nested spatial loops inside `CancerInvasionSteppables.py`. This prevents overhead from Python handling C++ out-of-bounds exceptions. Added unit test and journal entry. Co-authored-by: NoWon1 <126711057+NoWon1@users.noreply.github.com> --- .jules/bolt.md | 3 + Simulation/CancerInvasionSteppables.py | 52 ++++++------- .../CancerInvasionSteppables.cpython-312.pyc | Bin 23132 -> 23311 bytes test_cancer_invasion.py | 71 ++++++++++++++++++ 4 files changed, 95 insertions(+), 31 deletions(-) create mode 100644 .jules/bolt.md create mode 100644 test_cancer_invasion.py diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..48cce9c --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2024-05-18 - Optimize CC3D SWIG Array Lookups +**Learning:** In CompuCell3D (CC3D) Python scripts, using `try...except` blocks inside tightly nested spatial loops for field accesses (like `self.cell_field`) incurs significant overhead. Out-of-bounds SWIG object lookups throw exceptions that are costly to handle inside hot loops. +**Action:** Replace bare `except:` blocks around array accesses in spatial loops with explicit boundary checks (e.g., `0 <= x < self.dim.x`) before accessing arrays to significantly improve performance. diff --git a/Simulation/CancerInvasionSteppables.py b/Simulation/CancerInvasionSteppables.py index 3782ab5..baab75d 100644 --- a/Simulation/CancerInvasionSteppables.py +++ b/Simulation/CancerInvasionSteppables.py @@ -89,13 +89,11 @@ def initialize_paper_ecm(self): pixels_assigned = 0 for x, y in fiber_pixels: - try: + if 0 <= x < 500 and 0 <= y < 500: if self.cell_field[x, y, 0] is None: self.cell_field[x, y, 0] = fiber_cell self.fiber_locations.add((x, y)) pixels_assigned += 1 - except: - continue if pixels_assigned >= 10: fibers_created += 1 @@ -176,12 +174,9 @@ def create_paper_cell(self, center_x, center_y, radius): if dx*dx + dy*dy <= radius*radius: px, py = center_x + dx, center_y + dy if 0 <= px < 500 and 0 <= py < 500: - try: - if self.cell_field[px, py, 0] is None: - self.cell_field[px, py, 0] = cell - pixels_added += 1 - except: - continue + if self.cell_field[px, py, 0] is None: + self.cell_field[px, py, 0] = cell + pixels_added += 1 if pixels_added >= 20: return True @@ -210,12 +205,10 @@ def safe_cell_removal(self, cell): min(self.dim.x, int(cell.xCOM) + search_radius)): for y in range(max(0, int(cell.yCOM) - search_radius), min(self.dim.y, int(cell.yCOM) + search_radius)): - try: + if 0 <= x < self.dim.x and 0 <= y < self.dim.y: if self.cell_field[x, y, 0] == cell: self.cell_field[x, y, 0] = None pixels_cleared += 1 - except: - continue return pixels_cleared > 0 except Exception as e: return False @@ -285,16 +278,13 @@ def paper_mmp_system(self): fibers_to_remove = [] for cell in self.cell_list: if cell.type == self.ECMFIBER: - try: - cx, cy = int(cell.xCOM), int(cell.yCOM) - if 0 <= cx < 500 and 0 <= cy < 500: - mmp_conc = mmp_field[cx, cy, 0] - if mmp_conc >= self.degradation_threshold: - fibers_to_remove.append(cell) - # Paper: reduce MMP count by 1 after degradation - mmp_field[cx, cy, 0] = max(0, mmp_conc - 1) - except: - continue + cx, cy = int(cell.xCOM), int(cell.yCOM) + if 0 <= cx < 500 and 0 <= cy < 500: + mmp_conc = mmp_field[cx, cy, 0] + if mmp_conc >= self.degradation_threshold: + fibers_to_remove.append(cell) + # Paper: reduce MMP count by 1 after degradation + mmp_field[cx, cy, 0] = max(0, mmp_conc - 1) # Remove degraded fibers for fiber in fibers_to_remove: @@ -313,12 +303,9 @@ def check_ecm_contact(self, cell): for dy in range(-3, 4): nx, ny = cx + dx, cy + dy if 0 <= nx < 500 and 0 <= ny < 500: - try: - neighbor = self.cell_field[nx, ny, 0] - if neighbor and neighbor.type == self.ECMFIBER: - return True - except: - continue + neighbor = self.cell_field[nx, ny, 0] + if neighbor and neighbor.type == self.ECMFIBER: + return True return False except: return False @@ -371,11 +358,14 @@ def step(self, mcs): contact_area += commonSurfaceArea if contact_area < self.crowding_threshold: - try: - mmp_conc = self.field.MMP[int(cell.xCOM), int(cell.yCOM), 0] + cx, cy = int(cell.xCOM), int(cell.yCOM) + dim_x = getattr(self.dim, 'x', 500) + dim_y = getattr(self.dim, 'y', 500) + if 0 <= cx < dim_x and 0 <= cy < dim_y: + mmp_conc = self.field.MMP[cx, cy, 0] growth_boost = 1.0 + (mmp_conc * 0.1) cell.targetVolume += self.growth_rate * growth_boost - except: + else: cell.targetVolume += self.growth_rate diff --git a/Simulation/__pycache__/CancerInvasionSteppables.cpython-312.pyc b/Simulation/__pycache__/CancerInvasionSteppables.cpython-312.pyc index 611fe30ff6b01eb6d173b237652c7ed2be9fb237..d58d68dfc6f8350979e789e2a39a282c385d2168 100644 GIT binary patch delta 4078 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