Skip to content

Commit

Permalink
Merge branch 'qgaussian_derivative' into release/v0.21.3
Browse files Browse the repository at this point in the history
  • Loading branch information
szymonlopaciuk committed Nov 29, 2024
2 parents 46b742e + f760b68 commit c566db4
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 1 deletion.
1 change: 1 addition & 0 deletions contributors_and_credits.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ CERN contributors:
- K. Paraschou
- M. Schwinzerl
- F. Soubelet
- E. Waagaard

The Particle In Cell implementation is largely based on the PyPIC package (https://github.com/pycomplete/pypic)
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# copyright ################################# #
# This file is part of the Xfields Package. #
# Copyright (c) CERN, 2021. #
# ########################################### #

import numpy as np
from xfields import LongitudinalProfileQGaussian
import xobjects as xo
import matplotlib.pyplot as plt

plt.rcParams.update(
{
"font.family": "serif",
"font.size": 20,
"axes.titlesize": 20,
"axes.labelsize": 18,
"xtick.labelsize": 18,
"ytick.labelsize": 18,
"legend.fontsize": 15,
"figure.titlesize": 20,
}
)

# Longitudinal example parameters
z0 = 0.1
sigma_z = 0.2
npart = 1e11

test_context = xo.ContextCpu()
#test_context = xo.ContextCupy()

for qq in [0.0, 0.5, 0.95, 1.05, 1.3]:
lprofile = LongitudinalProfileQGaussian(
_context=test_context,
number_of_particles=npart,
sigma_z=sigma_z,
z0=z0,
q_parameter=qq)

# Select range relevant for derivative continuity
if qq < 1:
z = np.linspace(-0.347, 0.5, 1_000_000)
else:
z = np.linspace(-3., 3., 1_000_000)
z_dev = test_context.nparray_to_context_array(z)
lden_dev = lprofile.line_density(z_dev)
lden = test_context.nparray_from_context_array(lden_dev)

lderivative_dev = lprofile.line_derivative(z_dev)
lderivative = test_context.nparray_from_context_array(lderivative_dev)

numerical_derivative = np.gradient(lden, z)

print('q = {:.2f} max relative difference anal. vs num. : {:.3e}'.format(qq, max((lderivative - numerical_derivative) / numerical_derivative)))

fig, ax = plt.subplots(1, 1, figsize=(8, 6))
ax.plot(z, lderivative, label='Analytical derivative')
ax.plot(z, numerical_derivative, ls='--', label='Numerical derivative')
ax.text(0.83, 0.92, 'q={:.2f}'.format(qq), color='k', fontsize=15.5, transform=ax.transAxes)
ax.set_ylabel('Function value')
ax.set_xlabel('Zeta [m]')
ax.legend(loc='lower left')
plt.show()
30 changes: 30 additions & 0 deletions tests/test_profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,33 @@ def test_qgauss(test_context):
assert np.isclose(area, npart)
assert np.isclose(z_mean, z0)
assert np.isclose(z_std, sigma_z)

@for_all_test_contexts
def test_qgauss_derivative(test_context):
z0 = 0.1
sigma_z = 0.2
npart = 1e11

for qq in [0, 0.5, 0.95, 1.05, 1.3]:
lprofile = LongitudinalProfileQGaussian(
_context=test_context,
number_of_particles=npart,
sigma_z=sigma_z,
z0=z0,
q_parameter=qq)

# Select range relevant for derivative continuity
if qq < 1:
z = np.linspace(-0.347, 0.5, 1_000_000)
else:
z = np.linspace(-3., 3., 1_000_000)
z_dev = test_context.nparray_to_context_array(z)
lden_dev = lprofile.line_density(z_dev)
lden = test_context.nparray_from_context_array(lden_dev)

lderivative_dev = lprofile.line_derivative(z_dev)
lderivative = test_context.nparray_from_context_array(lderivative_dev)

numerical_derivative = np.gradient(lden, z)

assert np.isclose(lderivative, numerical_derivative, rtol=1e-5, atol=1e3).all()
17 changes: 17 additions & 0 deletions xfields/longitudinal_profiles/qgaussian.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ class LongitudinalProfileQGaussian(xo.HybridClass):
]

_kernels = {'line_density_qgauss':
xo.Kernel(args=[xo.Arg(xo.ThisClass, name='prof'),
xo.Arg(xo.Int64, name='n'),
xo.Arg(xo.Float64, pointer=True, name='z'),
xo.Arg(xo.Float64, pointer=True, name='res')],
n_threads='n'),
'line_derivative_qgauss':
xo.Kernel(args=[xo.Arg(xo.ThisClass, name='prof'),
xo.Arg(xo.Int64, name='n'),
xo.Arg(xo.Float64, pointer=True, name='z'),
Expand Down Expand Up @@ -177,4 +183,15 @@ def line_density(self, z):
context.kernels.line_density_qgauss(prof=self._xobject, n=len(z), z=z, res=res)

return res

def line_derivative(self, z):
context = self._buffer.context
res = context.zeros(len(z), dtype=np.float64)

if 'line_derivative_qgauss' not in context.kernels.keys():
self.compile_kernels()

context.kernels.line_derivative_qgauss(prof=self._xobject, n=len(z), z=z, res=res)

return res

20 changes: 19 additions & 1 deletion xfields/longitudinal_profiles/qgaussian_src/qgaussian.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,10 @@ double LongitudinalProfileQGaussian_line_density_derivative_scalar(
else{
double exponent = 1./(1.-q);
if (z<z_max && z>z_min){
return -9999.0;
double z_m_z0 = z - z0;
double q_exp_arg = -(beta_param*z_m_z0*z_m_z0 );
double q_exp_res = pow((1.+(1.-q)*q_exp_arg), exponent-1.);
return -2*factor*beta_param*z_m_z0*q_exp_res;
}
else{
return 0;
Expand All @@ -104,4 +107,19 @@ void line_density_qgauss(LongitudinalProfileQGaussianData prof,
}//end_vectorize
}


/*gpukern*/
void line_derivative_qgauss(LongitudinalProfileQGaussianData prof,
const int64_t n,
/*gpuglmem*/ const double* z,
/*gpuglmem*/ double* res){

#pragma omp parallel for //only_for_context cpu_openmp
for(int ii; ii<n; ii++){ //vectorize_over ii n

res[ii] = LongitudinalProfileQGaussian_line_density_derivative_scalar(prof, z[ii]);

}//end_vectorize
}

#endif

0 comments on commit c566db4

Please sign in to comment.