diff --git a/post-process/PythonScripts/geometryXVx/sheath/plot_conservation_energy b/post-process/PythonScripts/geometryXVx/sheath/plot_conservation_energy index c971b3d02..a59c56eae 100755 --- a/post-process/PythonScripts/geometryXVx/sheath/plot_conservation_energy +++ b/post-process/PythonScripts/geometryXVx/sheath/plot_conservation_energy @@ -15,7 +15,7 @@ import numpy as np from gysdata import DiskStore from plot_utils import plot_field1d, plot_field2d from math_utils import compute_moment, differentiate -from geometryXVx.utils import compute_krook_sink_constant, compute_kinetic_source +from geometryXVx.utils import compute_krook_sink_constant, compute_krook_sink_adaptive, compute_kinetic_source if __name__ == '__main__': @@ -53,6 +53,7 @@ if __name__ == '__main__': grad_flux_over_m = differentiate(energy_flux, 'x') / np.sqrt(mass) force_term = 2*particle_flux*charge/np.sqrt(mass)*electric_field energy_source = compute_moment(compute_krook_sink_constant(ds), 'v_x', moment_order=2) \ + + compute_moment(compute_krook_sink_adaptive(ds, density), 'v_x', moment_order=2) \ + compute_moment(compute_kinetic_source(ds), 'v_x', moment_order=2) error = dmomentum_flux_dt + grad_flux_over_m - energy_source - force_term diff --git a/post-process/PythonScripts/geometryXVx/sheath/plot_conservation_mass b/post-process/PythonScripts/geometryXVx/sheath/plot_conservation_mass index fee49f7e3..7ce83c4d7 100755 --- a/post-process/PythonScripts/geometryXVx/sheath/plot_conservation_mass +++ b/post-process/PythonScripts/geometryXVx/sheath/plot_conservation_mass @@ -14,7 +14,7 @@ import numpy as np from gysdata import DiskStore from plot_utils import plot_field1d, plot_field2d from math_utils import compute_moment, differentiate -from geometryXVx.utils import compute_krook_sink_constant, compute_kinetic_source +from geometryXVx.utils import compute_krook_sink_constant, compute_krook_sink_adaptive, compute_kinetic_source if __name__ == '__main__': @@ -48,6 +48,7 @@ if __name__ == '__main__': dn_dt = differentiate(density, 'time') grad_flux_over_m = differentiate(particle_flux, 'x') / np.sqrt(masses) mass_source = compute_moment(compute_krook_sink_constant(ds), 'v_x', moment_order=0) \ + + compute_moment(compute_krook_sink_adaptive(ds, density), 'v_x', moment_order=0) \ + compute_moment(compute_kinetic_source(ds), 'v_x', moment_order=0) error = dn_dt + grad_flux_over_m - mass_source diff --git a/post-process/PythonScripts/geometryXVx/sheath/plot_conservation_momentum b/post-process/PythonScripts/geometryXVx/sheath/plot_conservation_momentum index 9135060c4..f60352a63 100755 --- a/post-process/PythonScripts/geometryXVx/sheath/plot_conservation_momentum +++ b/post-process/PythonScripts/geometryXVx/sheath/plot_conservation_momentum @@ -16,7 +16,7 @@ import numpy as np from gysdata import DiskStore from plot_utils import plot_field1d, plot_field2d from math_utils import compute_moment, differentiate -from geometryXVx.utils import compute_krook_sink_constant, compute_kinetic_source +from geometryXVx.utils import compute_krook_sink_constant, compute_krook_sink_adaptive, compute_kinetic_source if __name__ == '__main__': @@ -53,6 +53,7 @@ if __name__ == '__main__': grad_flux_over_m = differentiate(momentum_flux, 'x') / np.sqrt(mass) force_term = density*charge/np.sqrt(mass)*electric_field momentum_source = compute_moment(compute_krook_sink_constant(ds), 'v_x', moment_order=1) \ + + compute_moment(compute_krook_sink_adaptive(ds, density), 'v_x', moment_order=1) \ + compute_moment(compute_kinetic_source(ds), 'v_x', moment_order=1) error = dgamma_dt + grad_flux_over_m - momentum_source - force_term diff --git a/post-process/PythonScripts/geometryXVx/utils.py b/post-process/PythonScripts/geometryXVx/utils.py index 701b066a6..8dc28db82 100644 --- a/post-process/PythonScripts/geometryXVx/utils.py +++ b/post-process/PythonScripts/geometryXVx/utils.py @@ -1,13 +1,17 @@ -# SPDX-License-Identifier: MIT +""" +SPDX-License-Identifier: MIT +Utility functions for geometryXVx post-process scripts. +""" import os import yaml +import xarray as xr def get_simulation_parameters(path, filename): '''Parses a yaml file containing the simulation parameters ''' - with open(os.path.join(path, filename)) as file: + with open(os.path.join(path, filename), encoding='utf8') as file: data = yaml.safe_load(file) if len(data['SpeciesInfo']) != 2: @@ -20,25 +24,65 @@ def get_simulation_parameters(path, filename): def compute_fluid_velocity(density, particle_flux): + '''Computes the fluid velocity moment + ''' return particle_flux / density def compute_pressure(density, particle_flux, momentum_flux): + '''Computes the pressure moment + ''' fluid_velocity = particle_flux / density return momentum_flux - particle_flux*fluid_velocity def compute_temperature(density, particle_flux, momentum_flux): + '''Computes the temperature moment + ''' return compute_pressure(density, particle_flux, momentum_flux) / density def compute_krook_sink_constant(diskstore): - nu = diskstore['krook_sink_constant_amplitude'] - mask = diskstore['krook_sink_constant_mask'] - ftarget = diskstore['krook_sink_constant_ftarget'] + '''Computes the constant krook sink expression + ''' + try: + nu = diskstore['krook_sink_constant_amplitude'] + mask = diskstore['krook_sink_constant_mask'] + ftarget = diskstore['krook_sink_constant_ftarget'] + + except KeyError as e: + print('Info: no constant krook sink in simulation:', e) + return xr.zeros_like(diskstore['fdistribu']) + + return -nu*mask*(diskstore['fdistribu']-ftarget) + + +def compute_krook_sink_adaptive(diskstore, density): + '''Computes the adaptive krook sink expression + ''' + try: + mask = diskstore['krook_sink_adaptive_mask'] + ftarget = diskstore['krook_sink_adaptive_ftarget'] + nu_ions = diskstore['krook_sink_adaptive_amplitude'] + density_target = diskstore['krook_sink_adaptive_density'] + nu = nu_ions*(density.sel(species='ions')-density_target) \ + / (density-density_target) + + except KeyError as e: + print('Info: no adaptive krook sink in simulation:', e) + return xr.zeros_like(diskstore['fdistribu']) + return -nu*mask*(diskstore['fdistribu']-ftarget) def compute_kinetic_source(diskstore): - return diskstore['kinetic_source_amplitude'] \ - * diskstore['kinetic_source_spatial_extent'] * diskstore['kinetic_source_velocity_shape'] + '''Computes the kinetic source expression + ''' + try: + return diskstore['kinetic_source_amplitude'] \ + * diskstore['kinetic_source_spatial_extent'] \ + * diskstore['kinetic_source_velocity_shape'] + except KeyError as e: + print('Info: no kinetic source in simulation:', e) + return xr.zeros_like(diskstore['fdistribu']) + diff --git a/post-process/PythonScripts/gysdata/data_structure_sheath.yaml b/post-process/PythonScripts/gysdata/data_structure_sheath.yaml index 9f37299c2..a22a3e91b 100644 --- a/post-process/PythonScripts/gysdata/data_structure_sheath.yaml +++ b/post-process/PythonScripts/gysdata/data_structure_sheath.yaml @@ -49,6 +49,22 @@ krook_sink_constant_ftarget: dimensions: [ *vxd ] path: { file: 'VOICEXX_initstate.h5', dataset: 'krook_sink_constant_ftarget' } +krook_sink_adaptive_amplitude: + dimensions: [ ] + path: { file: 'VOICEXX_initstate.h5', dataset: 'krook_sink_adaptive_amplitude' } + +krook_sink_adaptive_mask: + dimensions: [ *xd ] + path: { file: 'VOICEXX_initstate.h5', dataset: 'krook_sink_adaptive_mask' } + +krook_sink_adaptive_ftarget: + dimensions: [ *vxd ] + path: { file: 'VOICEXX_initstate.h5', dataset: 'krook_sink_adaptive_ftarget' } + +krook_sink_adaptive_density: + dimensions: [ ] + path: { file: 'VOICEXX_initstate.h5', dataset: 'krook_sink_adaptive_density' } + kinetic_source_amplitude: dimensions: [ ] path: { file: 'VOICEXX_initstate.h5', dataset: 'kinetic_source_amplitude' } diff --git a/simulations/geometryXVx/sheath/README.md b/simulations/geometryXVx/sheath/README.md index a497ee111..bc9c71c78 100644 --- a/simulations/geometryXVx/sheath/README.md +++ b/simulations/geometryXVx/sheath/README.md @@ -13,6 +13,14 @@ Two sets of parameters are available : - the default parameter given in `sheath.yaml.hpp`. This cas corresponds to a very light simulation case that runs a few iterations for testing purposes. This is the set of parameters that can be retrieved with the `--dump-config` command. - the parameters given in the folder `ref_simulation`, in the `sheath_ref.yaml` file. This simulation presents a glimpse of the plasma-wall interaction physics that can be seen on the figures in the mentioned folder: formation of a positively charged layer in front of the wall region, accompanied by a drop of the electric potential that confines fast electrons. A particle flux going towards the wall exists in the plasma. With the number of iterations performed to obtain these figures, the system is not at steady state. To observe a steady state plasma-wall interaction with interesting physical features (supersonic flow of ions, truncation of fast velocity electrons, etc.) see the paramerers of [2]. +## Verification of the simulation +The accuracy of the physical results from a sheath simulation can be verified as follows. The simulation should be run with the parameters given in `sheath.yaml.hpp` file. Then, any conservation diagnostic can be used to test the accuracy of the results. For instance, a post-process script that breaks down the terms present in the equation of energy conservation is `post-process/PythonScripts/geometryXVx/sheath/plot_conservation_energy`. This script can be run as an executable in the folder containing the simulation results. In the simple XVx geometry The equation of energy conservation is written as + +$\partial_t \Pi_a + 1/\sqrt{A_a}\, \partial_x Q_a - 2\Gamma_a q_a E/\sqrt{A_a} = S_{e}$ + +Where $\Gamma_a$, $\Pi_a$ and $Q_a$ stand for the particle flux, momentum flux and energy flux of species $a$ (typically ions or electrons) respectively. These quantity are computed by the script using the distribution function of each species which is an output of the code. $A_a = m_e/m_a$ is the mass ratio of species $a$, and $q_a$ represents its charge ($+e$ for ions, $-e$ for electrons with $e$ the elementary charge). $E$ is the electric field, and $S_{e}$ the energy source term. The script plots all of the terms that appear in the energy conservation equation, along with the error (denoted as `lhs-rhs`) defined as being the left-hand-side term minus the right-hand-side terms, i.e. +$lhs-rhs = \partial_t \Pi_a + 1/\sqrt{A_a}\, \partial_x Q_a - 2\Gamma_a q_a E/\sqrt{A_a} - S_{e}$. This error term is plotted as well, and thus a simulation can be verified by ensuring that this error remains small as compared to the other terms. It is recommended to look at the conservation equation for electrons first, since as the lightest species, the numerical error is larger. The script also produces a 2D map of the error as a function of time and space. One shall note that in order to compute the time derivative term $\partial_t \Pi_a$, it is important to save all of the timesteps of the simulations, i.e. the parameters `time_diag` and `deltat` should be equal, as in the `sheath.yaml.hpp` file. Lastly, if one wishes to test a simulation that is faster, the number of iterations can be reduced to 10 for instance. The folder `conservation_plots` contains the graphs of the conservation equations computed using a simulation with the parameters of the `sheath.yaml.hpp` file. + ## References - [1] E. Bourne, Y. Munschy, V. Grandgirard, M. Mehrenberger, and P. Ghendrih, Non-Uniform Splines for Semi-Lagrangian Kinetic Simulations of the Plasma Sheath (2022) - [2] Y. Munschy, E. Bourne, P. Ghendrih, G. Dif-Pradalier, Y. Sarazin, V. Grandgirard, and P. Donnel, Kinetic plasma-wall interaction using immersed boundary conditions (2023) diff --git a/simulations/geometryXVx/sheath/conservations_plots/energy_conservation_error_electrons_t5.0.png b/simulations/geometryXVx/sheath/conservations_plots/energy_conservation_error_electrons_t5.0.png new file mode 100644 index 000000000..17f6d94e5 Binary files /dev/null and b/simulations/geometryXVx/sheath/conservations_plots/energy_conservation_error_electrons_t5.0.png differ diff --git a/simulations/geometryXVx/sheath/conservations_plots/energy_conservation_error_electrons_xt.png b/simulations/geometryXVx/sheath/conservations_plots/energy_conservation_error_electrons_xt.png new file mode 100644 index 000000000..21c3e7c22 Binary files /dev/null and b/simulations/geometryXVx/sheath/conservations_plots/energy_conservation_error_electrons_xt.png differ diff --git a/simulations/geometryXVx/sheath/conservations_plots/energy_conservation_error_ions_t5.0.png b/simulations/geometryXVx/sheath/conservations_plots/energy_conservation_error_ions_t5.0.png new file mode 100644 index 000000000..341c13064 Binary files /dev/null and b/simulations/geometryXVx/sheath/conservations_plots/energy_conservation_error_ions_t5.0.png differ diff --git a/simulations/geometryXVx/sheath/conservations_plots/energy_conservation_error_ions_xt.png b/simulations/geometryXVx/sheath/conservations_plots/energy_conservation_error_ions_xt.png new file mode 100644 index 000000000..535867859 Binary files /dev/null and b/simulations/geometryXVx/sheath/conservations_plots/energy_conservation_error_ions_xt.png differ diff --git a/simulations/geometryXVx/sheath/conservations_plots/mass_conservation_error_electrons_t5.0.png b/simulations/geometryXVx/sheath/conservations_plots/mass_conservation_error_electrons_t5.0.png new file mode 100644 index 000000000..26f30fe58 Binary files /dev/null and b/simulations/geometryXVx/sheath/conservations_plots/mass_conservation_error_electrons_t5.0.png differ diff --git a/simulations/geometryXVx/sheath/conservations_plots/mass_conservation_error_electrons_xt.png b/simulations/geometryXVx/sheath/conservations_plots/mass_conservation_error_electrons_xt.png new file mode 100644 index 000000000..fee0136e1 Binary files /dev/null and b/simulations/geometryXVx/sheath/conservations_plots/mass_conservation_error_electrons_xt.png differ diff --git a/simulations/geometryXVx/sheath/conservations_plots/mass_conservation_error_ions_t5.0.png b/simulations/geometryXVx/sheath/conservations_plots/mass_conservation_error_ions_t5.0.png new file mode 100644 index 000000000..a3732316c Binary files /dev/null and b/simulations/geometryXVx/sheath/conservations_plots/mass_conservation_error_ions_t5.0.png differ diff --git a/simulations/geometryXVx/sheath/conservations_plots/mass_conservation_error_ions_xt.png b/simulations/geometryXVx/sheath/conservations_plots/mass_conservation_error_ions_xt.png new file mode 100644 index 000000000..6161bdf69 Binary files /dev/null and b/simulations/geometryXVx/sheath/conservations_plots/mass_conservation_error_ions_xt.png differ diff --git a/simulations/geometryXVx/sheath/conservations_plots/momentum_conservation_error_electrons_t5.0.png b/simulations/geometryXVx/sheath/conservations_plots/momentum_conservation_error_electrons_t5.0.png new file mode 100644 index 000000000..786c10e96 Binary files /dev/null and b/simulations/geometryXVx/sheath/conservations_plots/momentum_conservation_error_electrons_t5.0.png differ diff --git a/simulations/geometryXVx/sheath/conservations_plots/momentum_conservation_error_electrons_xt.png b/simulations/geometryXVx/sheath/conservations_plots/momentum_conservation_error_electrons_xt.png new file mode 100644 index 000000000..955aa7467 Binary files /dev/null and b/simulations/geometryXVx/sheath/conservations_plots/momentum_conservation_error_electrons_xt.png differ diff --git a/simulations/geometryXVx/sheath/conservations_plots/momentum_conservation_error_ions_t5.0.png b/simulations/geometryXVx/sheath/conservations_plots/momentum_conservation_error_ions_t5.0.png new file mode 100644 index 000000000..3f6eabb8e Binary files /dev/null and b/simulations/geometryXVx/sheath/conservations_plots/momentum_conservation_error_ions_t5.0.png differ diff --git a/simulations/geometryXVx/sheath/conservations_plots/momentum_conservation_error_ions_xt.png b/simulations/geometryXVx/sheath/conservations_plots/momentum_conservation_error_ions_xt.png new file mode 100644 index 000000000..60148cd10 Binary files /dev/null and b/simulations/geometryXVx/sheath/conservations_plots/momentum_conservation_error_ions_xt.png differ diff --git a/simulations/geometryXVx/sheath/pdi_out.yml.hpp b/simulations/geometryXVx/sheath/pdi_out.yml.hpp index 60ed6f5b0..bfbac933f 100644 --- a/simulations/geometryXVx/sheath/pdi_out.yml.hpp +++ b/simulations/geometryXVx/sheath/pdi_out.yml.hpp @@ -37,6 +37,22 @@ constexpr char const* const PDI_CFG = R"PDI_CFG( size: [ '$fdistribu_eq_extents[0]', '$fdistribu_eq_extents[1]' ] collintra_nustar0 : double + krook_sink_adaptive_extent : double + krook_sink_adaptive_stiffness : double + krook_sink_adaptive_amplitude : double + krook_sink_adaptive_density : double + krook_sink_adaptive_temperature : double + krook_sink_adaptive_mask_extents: { type: array, subtype: int64, size: 1 } + krook_sink_adaptive_mask: + type: array + subtype: double + size: [ '$krook_sink_adaptive_mask_extents[0]' ] + krook_sink_adaptive_ftarget_extents: { type: array, subtype: int64, size: 1 } + krook_sink_adaptive_ftarget: + type: array + subtype: double + size: [ '$krook_sink_adaptive_ftarget_extents[0]' ] + krook_sink_constant_extent : double krook_sink_constant_stiffness : double krook_sink_constant_amplitude : double @@ -109,6 +125,14 @@ constexpr char const* const PDI_CFG = R"PDI_CFG( - fdistribu_masses - fdistribu_eq + - krook_sink_adaptive_extent + - krook_sink_adaptive_stiffness + - krook_sink_adaptive_amplitude + - krook_sink_adaptive_density + - krook_sink_adaptive_temperature + - krook_sink_adaptive_mask + - krook_sink_adaptive_ftarget + - krook_sink_constant_extent - krook_sink_constant_stiffness - krook_sink_constant_amplitude diff --git a/simulations/geometryXVx/sheath/sheath.yaml.hpp b/simulations/geometryXVx/sheath/sheath.yaml.hpp index 6e75b514e..8f4e13633 100644 --- a/simulations/geometryXVx/sheath/sheath.yaml.hpp +++ b/simulations/geometryXVx/sheath/sheath.yaml.hpp @@ -28,7 +28,7 @@ constexpr char const* const params_yaml = R"PARAMS_CFG(Mesh: perturb_mode: 1 Krook: - - name: 'constant' # 'constant' or adaptive': constant values or not for nu coeff. + - name: 'adaptive' # 'constant' or adaptive': constant values or not for nu coeff. type: 'sink' solver: 'rk2' # possible values : 'rk2' extent: 0.20 @@ -46,13 +46,13 @@ constexpr char const* const params_yaml = R"PARAMS_CFG(Mesh: temperature: 1. CollisionsInfo: - enable_inter: true + enable_inter: false nustar0: 0.1 Algorithm: deltat: 0.1 - nbiter: 100 + nbiter: 50 Output: - time_diag: 0.3 + time_diag: 0.1 )PARAMS_CFG";