#!/usr/bin/env python3 # # Copyright 2021 Remi Lehe # # This file is part of WarpX. # # License: BSD-3-Clause-LBNL """ This script tests the Gaussian-flux injection (and in particular the rejection method in WarpX that we use to generate the right velocity distribution). Two population of particles are injected, with a slightly different ratio of u_m/u_th. (This is in order to test the two different rejection methods implemented in WarpX, which depend on the u_m/u_th ratio.) After the particles are emitted with flux injection, this script produces histograms of the velocity distribution and compares it with the expected velocity distibution (Gaussian or Gaussian-flux depending on the direction of space) """ import os import re import sys import matplotlib.pyplot as plt import numpy as np from scipy.constants import c, m_e, m_p from scipy.special import erf import yt sys.path.insert(1, '../../../../warpx/Regression/Checksum/') import checksumAPI yt.funcs.mylog.setLevel(0) # Open plotfile specified in command line fn = sys.argv[1] ds = yt.load( fn ) ad = ds.all_data() t_max = ds.current_time.item() # time of simulation # Total number of electrons expected: # Simulation parameters determine the total number of particles emitted (Ntot) flux = 1. # in m^-2.s^-1, from the input script emission_surface = 8*8 # in m^2 Ntot = flux * emission_surface * t_max # Parameters of the histogram hist_bins = 50 hist_range = [-0.5, 0.5] # Define function that histogram and check the data def gaussian_dist(u, u_th): return 1./((2*np.pi)**.5*u_th) * np.exp(-u**2/(2*u_th**2) ) def gaussian_flux_dist(u, u_th, u_m): au_m = np.abs(u_m) normalization_factor = u_th**2 * np.exp(-au_m**2/(2*u_th**2)) + (np.pi/2)**.5*au_m*u_th * (1 + erf(au_m/(2**.5*u_th))) result = 1./normalization_factor * np.where( u>0, u * np.exp(-(u-au_m)**2/(2*u_th**2)), 0 ) if u_m < 0.: result = result[::-1] return result def compare_gaussian(u, w, u_th, label=''): du = (hist_range[1]-hist_range[0])/hist_bins w_hist, u_hist = np.histogram(u, bins=hist_bins, weights=w/du, range=hist_range) u_hist = 0.5*(u_hist[1:]+u_hist[:-1]) w_th = Ntot*gaussian_dist(u_hist, u_th) plt.plot( u_hist, w_hist, label=label+': simulation' ) plt.plot( u_hist, w_th, '--', label=label+': theory' ) assert np.allclose( w_hist, w_th, atol=0.07*w_th.max() ) def compare_gaussian_flux(u, w, u_th, u_m, label=''): du = (hist_range[1]-hist_range[0])/hist_bins w_hist, u_hist = np.histogram(u, bins=hist_bins, weights=w/du, range=hist_range) u_hist = 0.5*(u_hist[1:]+u_hist[:-1]) w_th = Ntot*gaussian_flux_dist(u_hist, u_th, u_m) plt.plot( u_hist, w_hist, label=label+': simulation' ) plt.plot( u_hist, w_th, '--', label=label+': theory' ) assert np.allclose( w_hist, w_th, atol=0.05*w_th.max() ) # Load data and perform check plt.figure(figsize=(5,7)) plt.subplot(211) plt.title('Electrons') ux = ad['electron','particle_momentum_x'].to_ndarray()/(m_e*c) uy = ad['electron','particle_momentum_y'].to_ndarray()/(m_e*c) uz = ad['electron','particle_momentum_z'].to_ndarray()/(m_e*c) w = ad['electron', 'particle_weight'].to_ndarray() compare_gaussian(ux, w, u_th=0.1, label='u_x') compare_gaussian_flux(uy, w, u_th=0.1, u_m=0.07, label='u_y') compare_gaussian(uz, w, u_th=0.1, label='u_z') plt.legend(loc=0) plt.subplot(212) plt.title('Protons') ux = ad['proton','particle_momentum_x'].to_ndarray()/(m_p*c) uy = ad['proton','particle_momentum_y'].to_ndarray()/(m_p*c) uz = ad['proton','particle_momentum_z'].to_ndarray()/(m_p*c) w = ad['proton', 'particle_weight'].to_ndarray() compare_gaussian_flux(ux, w, u_th=0.1, u_m=-0.05, label='u_x') compare_gaussian(uy, w, u_th=0.1, label='u_y') compare_gaussian(uz, w, u_th=0.1, label='u_z') plt.legend(loc=0) plt.savefig('Distribution.png') # Verify checksum test_name = os.path.split(os.getcwd())[1] if re.search( 'single_precision', fn ): checksumAPI.evaluate_checksum(test_name, fn, rtol=1.e-3) else: checksumAPI.evaluate_checksum(test_name, fn)