Skip to content

Commit bea297e

Browse files
committed
[Iter 104] Code modification in PDE_D.py
[Automated commit by Claude]
1 parent 0ac9e35 commit bea297e

1 file changed

Lines changed: 53 additions & 1 deletion

File tree

src/ParticleGraph/generators/PDE_D.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ class PDE_D(pyg.nn.MessagePassing):
3030
{"index": 3, "name": "B", "description": "Brusselator param B (used by mesh model)", "typical_range": [1.0, 10.0]},
3131
{"index": 4, "name": "mu", "description": "Morphological parameter (used by mesh model)", "typical_range": [0.01, 0.1]},
3232
{"index": 5, "name": "M1", "description": "Mobility coefficient for C1 gradients", "typical_range": [-16, 16]},
33-
{"index": 6, "name": "fdm_alpha", "description": "Field-dependent mobility strength (0=off, >0=faster at peaks, <0=slower at peaks)", "typical_range": [-2.0, 2.0]}
33+
{"index": 6, "name": "fdm_alpha", "description": "Field-dependent mobility strength (0=off, >0=faster at peaks, <0=slower at peaks)", "typical_range": [-2.0, 2.0]},
34+
{"index": 7, "name": "gdp_gamma", "description": "Gradient-dependent production strength (0=off, >0=particles at steep gradients consume/produce more)", "typical_range": [0.0, 2.0]}
3435
]
3536
},
3637
{
@@ -234,6 +235,34 @@ def __init__(self, aggr_type='mean', p=None, particle_params=None, bc_dpos=None,
234235
# Stored from mesh params row 0, index 2
235236
self.A_ref = p[0, 2]
236237

238+
# Block 14 code change: Gradient-dependent production (GDP)
239+
# p[0, 7] controls gdp_gamma (gradient-dependent production/consumption strength):
240+
# 0.0 = constant production/consumption rates (backward compatible, default)
241+
# >0 = rate_eff = rate * (1 + gdp_gamma * clamp(|grad_C1_local|, max=1.0))
242+
# Particles at pattern BOUNDARIES (steep gradients) consume/produce MORE
243+
# than particles at pattern CENTERS (flat gradients, near peaks/troughs).
244+
# Literature: Meinhardt (1982) "Models of Biological Pattern Formation" — gradient-
245+
# dependent production rates create edge-selective feedback in morphogen systems.
246+
# Also: Kondo & Miura (2010) Science 329:1616 — reaction-diffusion patterns are
247+
# stabilized when reaction rates depend on spatial context (gradient information).
248+
# Rationale: The 7/10 ceiling (104 iterations, Blocks 1-13) persists because
249+
# particle back-reaction (consumption/production) is spatially uniform. GDP makes
250+
# particles at pattern boundaries produce/consume more, creating edge-selective
251+
# feedback that sharpens morphological features. Combined with FDM (mobility
252+
# control) and multi-type opposing (segregation), GDP adds a third dimension
253+
# of spatial control: WHERE particles have their strongest effect on fields.
254+
# Effect: Particles at steep gradient boundaries become production/consumption
255+
# hotspots, reinforcing boundary regions. Particles at flat peaks/troughs have
256+
# weaker back-reaction. This creates differential feedback: boundaries are
257+
# reinforced, centers are relatively unaffected → sharper, more complex features.
258+
if p.shape[1] > 7:
259+
self.gdp_gamma = p[0, 7]
260+
else:
261+
self.gdp_gamma = 0.0
262+
263+
# Storage for local gradient magnitude, computed during 'fp' pass for use in 'pf' pass
264+
self._local_grad_mag = None
265+
237266
# Report configuration
238267
print(f"initialized PDE_D with parameters:")
239268
print(f"mobility: M₁={self.M1.item()}, M₂={self.M2.item()}")
@@ -293,6 +322,12 @@ def __init__(self, aggr_type='mean', p=None, particle_params=None, bc_dpos=None,
293322
print(f"field-dependent mobility (FDM): alpha={fdm_val:.3f} (M_eff = M*(1+alpha*clamp((C1-A)^2/A^2,max=4)), Hillen & Painter 2009)")
294323
else:
295324
print(f"field-dependent mobility: off (alpha=0)")
325+
if hasattr(self, 'gdp_gamma'):
326+
gdp_val = self.gdp_gamma.item() if hasattr(self.gdp_gamma, 'item') else self.gdp_gamma
327+
if gdp_val > 0:
328+
print(f"gradient-dependent production (GDP): gamma={gdp_val:.3f} (rate_eff = rate*(1+gamma*clamp(|gradC1|,max=1)), Meinhardt 1982)")
329+
else:
330+
print(f"gradient-dependent production: off (gamma=0)")
296331
if particle_params is not None:
297332
print(f"multi-type support: {particle_params.shape[0]} particle types")
298333
print(f"per-type params: [M1, M2, consumption, production, ar_p1, ar_p2, ar_p3, ar_p4]")
@@ -540,6 +575,23 @@ def message(self, edge_index_i, edge_index_j, x_i, x_j, mode=None, parameters_i=
540575
consumption = consumption * mm_factor
541576
production = production * mm_factor
542577

578+
# Block 14: Gradient-dependent production (GDP)
579+
# Meinhardt (1982): gradient-dependent rates create edge-selective feedback
580+
# When gdp_gamma > 0, scale consumption/production by local gradient magnitude:
581+
# rate_eff = rate * (1 + gdp_gamma * clamp(|dC1/dr|, max=1.0))
582+
# Particles at pattern boundaries (steep gradients) have amplified rates.
583+
# Particles at pattern centers (flat, near peak/trough) have baseline rates.
584+
# Uses the C1 field difference along the pf edge as gradient proxy.
585+
if hasattr(self, 'gdp_gamma') and self.gdp_gamma > 0:
586+
# Compute local gradient magnitude from field difference along this edge
587+
C1_i = x_i[:, 6] # C1 at particle position
588+
C1_j = x_j[:, 6] # C1 at mesh node
589+
dC1_dr = torch.abs(C1_j - C1_i) / (dist_safe * 32.0) # Scaled gradient estimate
590+
grad_mag_clamped = torch.clamp(dC1_dr, max=1.0)
591+
gdp_factor = 1.0 + self.gdp_gamma * grad_mag_clamped
592+
consumption = consumption * gdp_factor
593+
production = production * gdp_factor
594+
543595
# Create field updates [C₁, C₂]
544596
field_updates = torch.zeros((pos_i.size(0), 2), device=pos_i.device)
545597
field_updates[:, 0] = -consumption * weights

0 commit comments

Comments
 (0)