"""Enfield poltergeist (P.1a) – agent‑based physical disturbances."""
import matplotlib.pyplot as plt
import numpy as np
from mercurial.core.neural_field import NeuralField2D
from mercurial.core.wilson_cowan import WilsonCowanPopulation
from mercurial.simulation.engine import SimulationEngine
[docs]
def run_enfield():
engine = SimulationEngine(dim=20)
engine.apply_empirical_parameters()
# 1. Agent: Wilson‑Cowan population representing emotional stress
agent = WilsonCowanPopulation(params=engine.wc_params, sigma=0.02)
stress_history = []
# 2. Environment: 2D neural field representing the house (32x32)
nx, ny = 32, 32
house_field = NeuralField2D(nx, ny, dx=0.5, wc_params=engine.wc_params.__dict__)
dt = 0.001
t_span = (0.0, 10.0) # simulate 10 seconds
steps = int((t_span[1] - t_span[0]) / dt)
# Agent’s stress level (external input) – high during emotional episodes
# We simulate stress peaks at random intervals (poltergeist bursts)
rng = np.random.default_rng(42)
stress_peak_times = [1.0, 2.5, 4.0, 5.5, 7.0, 8.5] # seconds
stress_amplitude = 5.0
# Record house field activity bursts (mean intensity over the field)
house_activity = []
for step in range(steps):
t = step * dt
# Determine agent’s external input (stress)
stress_input = 0.0
for peak in stress_peak_times:
if abs(t - peak) < 0.2: # 200 ms stress pulse
stress_input = stress_amplitude
agent.step(dt, P_ext=stress_input, Q_ext=0.0)
stress_history.append(agent.E) # excitatory activity = stress level
# Agent’s stress biases the house field (top‑down causation)
# Higher stress → stronger bias
bias_strength = 2.0 * agent.E
# Add a random spatial pattern (simulating the agent’s diffuse influence)
noise_pattern = rng.normal(0, 0.1, size=(nx, ny))
P_ext_house = bias_strength * (noise_pattern + 0.5) # non‑negative
house_field.step(dt, P_ext=P_ext_house)
house_activity.append(np.mean(house_field.E)) # mean field intensity
# Compute correlation between agent’s stress and house activity bursts
# (use a moving average to capture burst envelope)
from scipy.signal import savgol_filter
stress_smooth = savgol_filter(stress_history, window_length=51, polyorder=3)
house_smooth = savgol_filter(house_activity, window_length=51, polyorder=3)
correlation = np.corrcoef(stress_smooth, house_smooth)[0, 1]
print(f"Correlation between agent stress and house activity: {correlation:.3f}")
# Plot stress and house activity over time
time = np.arange(steps) * dt
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(time, stress_history, label="Agent stress (E)")
plt.xlabel("Time (s)")
plt.ylabel("Stress level")
plt.title("Agent's emotional stress")
plt.grid(True)
plt.subplot(1, 2, 2)
plt.plot(time, house_activity, label="House field activity", color="orange")
plt.xlabel("Time (s)")
plt.ylabel("Mean activity")
plt.title("House field activity bursts")
plt.grid(True)
plt.tight_layout()
plt.show()
return correlation
if __name__ == "__main__":
run_enfield()