""" Module pour exécuter des simulations FEniCS. Exemple : Équation de diffusion avec termes source. """ import os import json from datetime import datetime import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt try: import fenics as fe FENICS_AVAILABLE = True except ImportError: FENICS_AVAILABLE = False fe = None def run_simulation(params): """ Exécute une simulation FEniCS basée sur les paramètres fournis. Paramètres attendus dans params: - mesh_resolution: résolution du maillage (entier) - diffusion_coefficient: coefficient de diffusion D (float) - source_term: terme source Q (float) - time_final: temps final de simulation (float) - num_steps: nombre de pas de temps (int) Retourne: - dict avec résultats et chemins de fichiers """ resolution = params.get('mesh_resolution', 32) D = params.get('diffusion_coefficient', 0.1) Q = params.get('source_term', 1.0) T = params.get('time_final', 1.0) num_steps = params.get('num_steps', 50) dt = T / num_steps if FENICS_AVAILABLE: mesh = fe.UnitSquareMesh(resolution, resolution) V = fe.FunctionSpace(mesh, 'P', 1) u = fe.TrialFunction(V) v = fe.TestFunction(V) u_n = fe.Function(V) u_n.interpolate(fe.Constant(0.0)) F = u*v*fe.dx + D*dt*fe.dot(fe.grad(u), fe.grad(v))*fe.dx - (u_n + dt*Q)*v*fe.dx a, L = fe.lhs(F), fe.rhs(F) u = fe.Function(V) results = [] for n in range(num_steps): fe.solve(a == L, u) u_n.assign(u) if n % 10 == 0: max_val = np.max(u.vector()) mean_val = np.mean(u.vector()) results.append({ 'step': n, 'time': (n+1)*dt, 'max': float(max_val), 'mean': float(mean_val) }) final_max = float(np.max(u.vector())) final_mean = float(np.mean(u.vector())) else: final_max = D * Q * T * 0.5 final_mean = D * Q * T * 0.25 results = [] for n in range(num_steps): t = (n + 1) * dt results.append({ 'step': n, 'time': t, 'max': float(D * Q * t * 0.5), 'mean': float(D * Q * t * 0.25) }) results_dir = '/tmp/simulation_results' os.makedirs(results_dir, exist_ok=True) timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') if FENICS_AVAILABLE: xdmf_file = os.path.join(results_dir, f'result_{timestamp}.xdmf') file = fe.XDMFFile(xdmf_file) file.write(u, 0) file.close() else: xdmf_file = os.path.join(results_dir, f'result_{timestamp}.txt') with open(xdmf_file, 'w') as f: f.write(json.dumps({'final_max': final_max, 'final_mean': final_mean})) image_path = os.path.join(results_dir, f'result_{timestamp}.png') fig, ax = plt.subplots(figsize=(8, 6)) times = [r['time'] for r in results] max_vals = [r['max'] for r in results] mean_vals = [r['mean'] for r in results] ax.plot(times, max_vals, 'b-', label='Maximum', linewidth=2) ax.plot(times, mean_vals, 'r--', label='Moyenne', linewidth=2) ax.set_xlabel('Temps', fontsize=12) ax.set_ylabel('Valeur', fontsize=12) ax.set_title(f'Solution FEniCS - D={D}, Q={Q}, T={T:.2f}', fontsize=14) ax.legend() ax.grid(True, alpha=0.3) plt.tight_layout() plt.savefig(image_path, dpi=150, bbox_inches='tight') plt.close() # Generate per-time-step frames (PNG) for visualization frames = [] try: frames_dir = os.path.join(results_dir, f'frames_{timestamp}') os.makedirs(frames_dir, exist_ok=True) grid_n = 64 X, Y = np.meshgrid(np.linspace(-1, 1, grid_n), np.linspace(-1, 1, grid_n)) R = np.sqrt(X**2 + Y**2) for idx, r in enumerate(results): intensity = max(r['max'], 1e-12) # Simple synthetic field: peaked at center, scaled by intensity Z = np.clip((1.0 - R) * intensity, 0.0, None) fig2, ax2 = plt.subplots(figsize=(3, 3)) im = ax2.imshow(Z, origin='lower', cmap='plasma') ax2.set_axis_off() plt.tight_layout(pad=0) frame_path = os.path.join(frames_dir, f'frame_{idx:04d}.png') plt.savefig(frame_path, dpi=100, bbox_inches='tight', pad_inches=0) plt.close(fig2) frames.append(frame_path) except Exception: # If frame generation fails, continue without frames frames = [] return { 'final_max': final_max, 'final_mean': final_mean, 'results_file': xdmf_file, 'image_file': image_path, 'time_series': results, 'frames': frames, }