diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a60b85 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +*.pyc diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..fef6afa --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2024-05-18 - CompuCell3D Field Access Exceptions +**Learning:** In CompuCell3D Python scripts, avoid using `try...except` blocks inside tightly nested spatial loops for field accesses (like `self.cell_field`). Out-of-bounds SWIG object lookups throw exceptions that incur significant overhead. +**Action:** Use explicit boundary checks (e.g., `min()`, `max()`) before accessing arrays to avoid throwing/catching exceptions. diff --git a/Simulation/CancerInvasionSteppables.py b/Simulation/CancerInvasionSteppables.py index 3782ab5..662c006 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 < self.dim.x and 0 <= y < self.dim.y: 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 @@ -175,13 +173,10 @@ def create_paper_cell(self, center_x, center_y, radius): for dy in range(-radius, radius + 1): 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 0 <= px < self.dim.x and 0 <= py < self.dim.y: + 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 @@ -206,16 +201,15 @@ def safe_cell_removal(self, cell): try: pixels_cleared = 0 search_radius = 15 - for x in range(max(0, int(cell.xCOM) - search_radius), - 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 self.cell_field[x, y, 0] == cell: - self.cell_field[x, y, 0] = None - pixels_cleared += 1 - except: - continue + x_min = max(0, int(cell.xCOM) - search_radius) + x_max = min(self.dim.x, int(cell.xCOM) + search_radius) + y_min = max(0, int(cell.yCOM) - search_radius) + y_max = min(self.dim.y, int(cell.yCOM) + search_radius) + for x in range(x_min, x_max): + for y in range(y_min, y_max): + if self.cell_field[x, y, 0] == cell: + self.cell_field[x, y, 0] = None + pixels_cleared += 1 return pixels_cleared > 0 except Exception as e: return False @@ -285,16 +279,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 < self.dim.x and 0 <= cy < self.dim.y: + 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: @@ -309,16 +300,16 @@ def check_ecm_contact(self, cell): try: cx, cy = int(cell.xCOM), int(cell.yCOM) - for dx in range(-3, 4): - 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 + x_min = max(0, cx - 3) + x_max = min(self.dim.x, cx + 4) + y_min = max(0, cy - 3) + y_max = min(self.dim.y, cy + 4) + + for nx in range(x_min, x_max): + for ny in range(y_min, y_max): + neighbor = self.cell_field[nx, ny, 0] + if neighbor and neighbor.type == self.ECMFIBER: + return True return False except: return False @@ -371,11 +362,12 @@ 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) + if 0 <= cx < self.dim.x and 0 <= cy < self.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 deleted file mode 100644 index 611fe30..0000000 Binary files a/Simulation/__pycache__/CancerInvasionSteppables.cpython-312.pyc and /dev/null differ