Source code for mercurial.atlas.enfield_poltergeist_empirical

"""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()