|
149 | 149 | "\n", |
150 | 150 | "from simulation_diag_handler import Simulation, set_plot_defaults\n", |
151 | 151 | "\n", |
| 152 | + "sim = Simulation(\"/ZONE_TRAVAIL/RV255575/tokam2d_conservation/HW_cons_rst\")\n", |
| 153 | + "\n", |
152 | 154 | "set_plot_defaults()\n", |
153 | 155 | "\n", |
154 | 156 | "plt.close('all')\n", |
|
290 | 292 | "\n", |
291 | 293 | "sim.make_movie(field='density', path=None, filename='mysim', it_slice=None, parallel=True, num_cores=None, for_IA=False, scheme=None, cmap='plasma', vmin=None, vmax=None, fps=30, save_frames=False)" |
292 | 294 | ] |
| 295 | + }, |
| 296 | + { |
| 297 | + "cell_type": "markdown", |
| 298 | + "id": "869be0f0", |
| 299 | + "metadata": {}, |
| 300 | + "source": [ |
| 301 | + "## **Conservation**" |
| 302 | + ] |
| 303 | + }, |
| 304 | + { |
| 305 | + "cell_type": "markdown", |
| 306 | + "id": "175e983b", |
| 307 | + "metadata": {}, |
| 308 | + "source": [ |
| 309 | + "### **Compute energy conservation (Hasegawa-Wakatani)**\n", |
| 310 | + "\n", |
| 311 | + "\\begin{equation}\n", |
| 312 | + "\\frac{dE}{dt} = \\Gamma_n - D_\\alpha - D_E\n", |
| 313 | + "\\end{equation}\n", |
| 314 | + "\n", |
| 315 | + "Where \n", |
| 316 | + "\n", |
| 317 | + "\\begin{equation}\n", |
| 318 | + "E = \\frac{1}{2} \\int n^2 + |\\nabla \\phi|^2 \\, d\\mathbf{x}\n", |
| 319 | + "\\end{equation}\n", |
| 320 | + "\n", |
| 321 | + "The time derivative of the energy $E$ can be computed from saved data as\n", |
| 322 | + "\n", |
| 323 | + "\\begin{equation}\n", |
| 324 | + "\\frac{dE}{dt} = \\int \\left( n \\cdot \\frac{dn}{dt} \n", |
| 325 | + "+ |\\nabla_x \\phi| \\cdot \\frac{d |\\nabla_x \\phi|}{dt}\n", |
| 326 | + "+ |\\nabla_y \\phi| \\cdot \\frac{d |\\nabla_y \\phi|}{dt} \\right)\n", |
| 327 | + "\\, d\\mathbf{x}\n", |
| 328 | + "\\end{equation}\n", |
| 329 | + "\n", |
| 330 | + "and \n", |
| 331 | + "\n", |
| 332 | + "\\begin{equation}\n", |
| 333 | + "\\Gamma_n = -\\kappa \\int n \\cdot \\frac{\\partial \\phi}{\\partial y} \\, d\\mathbf{x} \\text{~~(``source'')}\n", |
| 334 | + "\\end{equation}\n", |
| 335 | + "\n", |
| 336 | + "\\begin{equation}\n", |
| 337 | + "D_C = C \\int (n - \\phi)^2 \\, d\\mathbf{x} \\text{~~(``coupling'')}\n", |
| 338 | + "\\end{equation}\n", |
| 339 | + "\n", |
| 340 | + "\\begin{equation}\n", |
| 341 | + "D_{E,n} = (-1)^{N_n} D_n \\int n \\nabla^{2N_n} n \\, d\\mathbf{x} \\text{~~(``density dissipation'')}\n", |
| 342 | + "\\end{equation}\n", |
| 343 | + "\n", |
| 344 | + "\\begin{equation}\n", |
| 345 | + "D_{E,\\Omega} = (-1)^{N_\\phi} D_\\phi \\int n \\nabla^{2N_\\phi+2} \\phi \\, d\\mathbf{x} \\text{~~(``vorticity dissipation'')}\n", |
| 346 | + "\\end{equation}\n", |
| 347 | + "\n", |
| 348 | + "**<span style=\"color:red\">\n", |
| 349 | + "/!\\ Some important notes\n", |
| 350 | + "</span>**\n", |
| 351 | + "\n", |
| 352 | + "- Accuracy of time derivatives are very important to compute the conservations. It is advised to switch on the 'compute_time_derivatives' in the simulation inputs (which computes the 8th order central finite difference from the rk4 time steps which are not available in the stored data outputs) and derive the time derivative of energy according to the formula above.\n", |
| 353 | + "\n", |
| 354 | + "- Semi-spectral code such as Tokam2D usually relies on a 2/3 dealiasing rule for avoid the emergence of spurious (non-physical) modes by truncating a part of high k (small scales) while the simulation is running.\n", |
| 355 | + "One consequence is that the energy transferred to these modes is lost.\n", |
| 356 | + "While the difference is (or should be) small, test cases for evaluating conservation properties of the code can be performed without this filter by switching of the 'fft_filter' in input file.\n", |
| 357 | + "\n", |
| 358 | + "- For Hasegawa-Wakatani schemes, noise accumulates during Tokam2D simulation and takes the form of non-zero imaginary part for some modes for the real space fields (which should be real signals). A filter is thus applied frequently during the simulation to remove this noise. Consequence on conservation are not clear.\n", |
| 359 | + "\n", |
| 360 | + "- Depending on the level of accuracy of conservation one needs, diminishing 'dt_rk4' (or equivalently increasing 'rk4_per_diag') in the input file should improve agreement. Increasing the spatial resolution 'Nx' and 'Ny', however, does not garantee a better conservation" |
| 361 | + ] |
| 362 | + }, |
| 363 | + { |
| 364 | + "cell_type": "code", |
| 365 | + "execution_count": null, |
| 366 | + "id": "9f70cf8a", |
| 367 | + "metadata": {}, |
| 368 | + "outputs": [], |
| 369 | + "source": [ |
| 370 | + "from simulation_diag_handler import Simulation, set_plot_defaults\n", |
| 371 | + "import numpy as np\n", |
| 372 | + "import matplotlib.pyplot as plt\n", |
| 373 | + "\n", |
| 374 | + "set_plot_defaults()\n", |
| 375 | + "\n", |
| 376 | + "## Fetch simulation data\n", |
| 377 | + "sim_path = '/path/to/sim'\n", |
| 378 | + "sim = Simulation(sim_path)\n", |
| 379 | + "\n", |
| 380 | + "## Define proxy function\n", |
| 381 | + "def rifft(x): return np.real(np.fft.ifft2(x, axes=(-2, -1)))\n", |
| 382 | + "\n", |
| 383 | + "## Choose\n", |
| 384 | + "it_beg = 0\n", |
| 385 | + "it_end = len(sim.time) - 1\n", |
| 386 | + "\n", |
| 387 | + "## Cast useful quantities\n", |
| 388 | + "potential_fft = sim.get_data_slice('potential_fft' , slice(it_beg, it_end))\n", |
| 389 | + "density_fft = sim.get_data_slice('density_fft' , slice(it_beg, it_end))\n", |
| 390 | + "density = sim.get_data_slice('density' , slice(it_beg, it_end))\n", |
| 391 | + "potential = sim.get_data_slice('potential' , slice(it_beg, it_end))\n", |
| 392 | + "dt_density = sim.get_data_slice('dt_density' , slice(it_beg, it_end))\n", |
| 393 | + "dt_potential = sim.get_data_slice('dt_potential' , slice(it_beg, it_end))\n", |
| 394 | + "dt_potential_fft = sim.get_data_slice('dt_potential_fft', slice(it_beg, it_end))\n", |
| 395 | + "kappa = sim[\"kappa\"][()]\n", |
| 396 | + "C = sim[\"C\"][()]\n", |
| 397 | + "D_n = sim[\"Dn\"][()][0]\n", |
| 398 | + "D_phi = sim[\"Dphi\"][()][0]\n", |
| 399 | + "N_n = 2 # 1: Diffusion, 2: Hyperdiffusion\n", |
| 400 | + "N_phi = 2 # 1: Diffusion, 2: Hyperdiffusion\n", |
| 401 | + "kx2D = sim.kx2D\n", |
| 402 | + "ky2D = sim.ky2D\n", |
| 403 | + "k2D = sim.k2D\n", |
| 404 | + "\n", |
| 405 | + "## Compute energy\n", |
| 406 | + "gradx_phi = rifft( (1j * kx2D) * potential_fft)\n", |
| 407 | + "grady_phi = rifft( (1j * ky2D) * potential_fft)\n", |
| 408 | + "energy = 0.5*np.mean(density**2 + (gradx_phi**2 + grady_phi**2), axis=(-2, -1))\n", |
| 409 | + "\n", |
| 410 | + "# FIGURE : time evolution of energy\n", |
| 411 | + "fig = plt.figure(figsize=(10,7))\n", |
| 412 | + "ax = fig.add_subplot(111)\n", |
| 413 | + "ax.plot(sim.time[it_beg:it_end], energy)\n", |
| 414 | + "ax.set_xlabel('Time')\n", |
| 415 | + "ax.set_ylabel('Energy')\n", |
| 416 | + "ax.set_title(f'Averaged between {sim.time[it_beg]:.2f} < t < {sim.time[it_end-1]:.2f}')\n", |
| 417 | + "\n", |
| 418 | + "## Compute terms of energy conservation equation \n", |
| 419 | + "# Energy time derivative\n", |
| 420 | + "dEdt_n = density * dt_density\n", |
| 421 | + "gradx_dt_phi = rifft( (1j * kx2D) * dt_potential_fft)\n", |
| 422 | + "grady_dt_phi = rifft( (1j * ky2D) * dt_potential_fft)\n", |
| 423 | + "dEdt_phi = gradx_phi * gradx_dt_phi + grady_phi * grady_dt_phi\n", |
| 424 | + "dEdt_avg = np.mean(dEdt_n + dEdt_phi, axis=(-2, -1))\n", |
| 425 | + "\n", |
| 426 | + "# Source term\n", |
| 427 | + "Gamma_n = - kappa * np.mean( density * grady_phi , axis=(-2, -1))\n", |
| 428 | + "\n", |
| 429 | + "# Coupling term\n", |
| 430 | + "D_C = C * np.mean( (density - potential)**2 , axis=(-2, -1))\n", |
| 431 | + "\n", |
| 432 | + "# Density dissipation\n", |
| 433 | + "nabla_2N_dens = rifft( (1j * k2D)**(2*N_n) * density_fft)\n", |
| 434 | + "DE_n = (-1)**N_n * D_n * np.mean(density * nabla_2N_dens, axis=(-2, -1))\n", |
| 435 | + "\n", |
| 436 | + "# Vorticity dissipation\n", |
| 437 | + "nabla_2N_vort = rifft( (1j * k2D)**(2*N_phi+2) * potential_fft)\n", |
| 438 | + "DE_vort = (-1)**N_phi * D_phi * np.mean(potential * nabla_2N_vort, axis=(-2, -1))\n", |
| 439 | + "\n", |
| 440 | + "# FIGURE : time evolution of energy conservation LHS and RHS\n", |
| 441 | + "fig = plt.figure(figsize=(10,7))\n", |
| 442 | + "ax = fig.add_subplot(111)\n", |
| 443 | + "ax.plot(sim.time[it_beg:it_end], dEdt_avg, ls='-',label=r'LHS: $\\partial_t E$')\n", |
| 444 | + "ax.plot(sim.time[it_beg:it_end], Gamma_n - D_C - DE_n + DE_vort, ls='--',label=r'RHS: $\\Gamma_n - D_C - D_{E,n} + D_{E,\\Omega}$')\n", |
| 445 | + "ax.set_xlabel('Time')\n", |
| 446 | + "ax.set_title(f'Averaged between {sim.time[it_beg]:.2f} < t < {sim.time[it_end-1]:.2f}')\n", |
| 447 | + "ax.legend()" |
| 448 | + ] |
293 | 449 | } |
294 | 450 | ], |
295 | 451 | "metadata": { |
|
0 commit comments