├── .gitignore ├── Bassetti_Erskine.py ├── FFT_OpenBoundary.py ├── FFT_OpenBoundary_SquareGrid.py ├── FFT_PEC_Boundary_SquareGrid.py ├── FPPS ├── ChangeCoord.cc ├── ChangeCoord.h ├── ChangeCoord_Frac.cc ├── ChangeCoord_Frac.h ├── ChangeCoord_Tanh.cc ├── ChangeCoord_Tanh.h ├── ChargeDistribution.cc ├── ChargeDistribution.h ├── CyFPPS.pyx ├── ElectricFieldSolver.cc ├── ElectricFieldSolver.h ├── FPPSWrapper.cc ├── FPPSWrapper.h ├── FastPolarPoissonSolver.cc ├── FastPolarPoissonSolver.h ├── FunctionsFPPS.cc ├── FunctionsFPPS.h ├── Mesh.cc ├── Mesh.h ├── NonLinearMesh.cc ├── NonLinearMesh.h ├── PolarBeamRepresentation.cc └── PolarBeamRepresentation.h ├── FiniteDifferences_ShortleyWeller_SquareGrid.py ├── FiniteDifferences_ShortleyWeller_SquareGrid_extrapolation.py ├── FiniteDifferences_Staircase_SquareGrid.py ├── GPU ├── .gitignore ├── Makefile ├── __init__.py ├── _version.py ├── backwards_compatibility_1_03.py ├── data │ └── Analyze_Timings.ipynb ├── geom_impact_ellip.py ├── geom_impact_poly.py ├── gradient │ ├── __init__.py │ ├── gradient.py │ └── gradient2.cu ├── itest │ ├── Itest_000_Round_Chamber.ipynb │ ├── Itest_003_Christmas_Tree.ipynb │ ├── Itest_006_time_solve.ipynb │ ├── PyPIC GPU Example improved_p2m.ipynb │ ├── PyPIC GPU Example.ipynb │ ├── Test_102_Backwards_compatibility.ipynb │ ├── Test_GPU_AtomicAdd_vs_Sorted.ipynb │ ├── Test_GPU_FFT_25D.ipynb │ ├── Test_GPU_FFT_2D.ipynb │ ├── Test_GPU_FFT_3D.ipynb │ └── Timings_2D.ipynb ├── m2p │ ├── __init__.py │ ├── interp_field_for.f │ ├── interp_field_for_with_border.f │ ├── m2p.py │ ├── m2p_kernels.cu │ └── m2p_kernels_inclmeshing.cu ├── meshing │ ├── __init__.py │ └── meshes.py ├── p2m │ ├── __init__.py │ ├── compute_rho.f │ ├── p2m.py │ ├── p2m_kernels.cu │ └── p2m_kernels_inclmeshing.cu ├── poisson_solver │ ├── FD_solver.py │ ├── FFT_solver.py │ ├── __init__.py │ ├── cusolver_Rf.py │ └── poisson_solver.py ├── pypic.py ├── setup.py ├── test │ ├── 000_test_round_chamber.py │ ├── 002_test_rect_chamber.py │ ├── 003_Xmas_tree.py │ ├── 004_test_gaussian.py │ ├── 005_testfftw.py │ ├── 006_time_solve.py │ ├── 007_test_separately.py │ ├── 008a_check_interpolation_near_borders.py │ ├── 008b_check_interpolation_near_borders_plots.py │ ├── 009_test_round_chamber_for_new_interp_devel.py │ ├── Bassetti_Erskine.py │ ├── __init__.py │ ├── myloadmat_to_obj.py │ ├── mystyle.py │ └── test_fft_gpu.ipynb └── vectsum.f ├── Makefile ├── MultiGrid.py ├── PyPIC_Scatter_Gather.py ├── __init__.py ├── change_version_number.py ├── compute_rho.f ├── errfff.f ├── generate_python3 ├── geom_impact_ellip.py ├── geom_impact_poly.py ├── interp_field_for.f ├── interp_field_for_with_border.f ├── myloadmat_to_obj.py ├── mystyle.py ├── setup.py ├── simple_polygon.py └── tests ├── 000_test_round_chamber.py ├── 002_test_rect_chamber.py ├── 003_Xmas_tree.py ├── 004_test_gaussian.py ├── 005_testfftw.py ├── 006_time_solve.py ├── 007_test_separately.py ├── 008a_check_interpolation_near_borders.py ├── 008b_check_interpolation_near_borders_plots.py ├── 009_test_round_chamber_for_new_interp_devel.py ├── 010_effect_of_tolerances_in_SW.py ├── 011_LHC_multigrid_test.py ├── 012_test_states.py └── LHC.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | *.pyc 3 | .project 4 | .pydevproject 5 | *.png 6 | norepository_* 7 | *~ 8 | build 9 | CyFPPS.cpp 10 | -------------------------------------------------------------------------------- /Bassetti_Erskine.py: -------------------------------------------------------------------------------- 1 | #---------------------------------------------------------------------- 2 | # 3 | # CERN 4 | # 5 | # European Organization for Nuclear Research 6 | # 7 | # 8 | # This file is part of the code 9 | # 10 | # 11 | # PyPIC Version 2.4.5 12 | # 13 | # 14 | # Author and contact: Giovanni IADAROLA 15 | # BE-ABP Group 16 | # CERN 17 | # CH-1211 GENEVA 23 18 | # SWITZERLAND 19 | # giovanni.iadarola@cern.ch 20 | # 21 | # contact: Giovanni RUMOLO 22 | # BE-ABP Group 23 | # CERN 24 | # CH-1211 GENEVA 23 25 | # SWITZERLAND 26 | # giovanni.rumolo@cern.ch 27 | # 28 | # 29 | # 30 | # Copyright CERN, Geneva 2011 - Copyright and any other 31 | # appropriate legal protection of this computer program and 32 | # associated documentation reserved in all countries of the 33 | # world. 34 | # 35 | # Organizations collaborating with CERN may receive this program 36 | # and documentation freely and without charge. 37 | # 38 | # CERN undertakes no obligation for the maintenance of this 39 | # program, nor responsibility for its correctness, and accepts 40 | # no liability whatsoever resulting from its use. 41 | # 42 | # Program and documentation are provided solely for the use of 43 | # the organization to which they are distributed. 44 | # 45 | # This program may not be copied or otherwise distributed 46 | # without permission. This message must be retained on this and 47 | # any other authorized copies. 48 | # 49 | # The material cannot be sold. CERN should be given credit in 50 | # all references. 51 | #---------------------------------------------------------------------- 52 | 53 | import numpy as np 54 | from .PyPIC_Scatter_Gather import PyPIC_Scatter_Gather 55 | from scipy.constants import e, epsilon_0 56 | from .errffor import errf 57 | 58 | 59 | qe = e 60 | eps0 = epsilon_0 61 | 62 | class Interpolated_Bassetti_Erskine(PyPIC_Scatter_Gather): 63 | #@profile 64 | def __init__(self, x_aper, y_aper, Dh, sigmax, sigmay, 65 | n_imag_ellip=0, tot_charge=1., verbose=True, allow_scatter_and_solve=False): 66 | 67 | self.verbose = verbose 68 | self.allow_scatter_and_solve = allow_scatter_and_solve 69 | 70 | if self.verbose: 71 | print('Start PIC init.:') 72 | print('Bassetti-Erskine, Square Grid') 73 | 74 | self.Dh = Dh 75 | super(Interpolated_Bassetti_Erskine, self).__init__(x_aper, y_aper, self.Dh, self.Dh, verbose=self.verbose) 76 | 77 | xx = self.xg 78 | yy = self.yg 79 | 80 | Ex=np.zeros((len(xx),len(yy)),dtype=complex); 81 | Ey=np.zeros((len(xx),len(yy)),dtype=complex); 82 | 83 | for ii in range(len(xx)): 84 | 85 | if np.mod(ii, len(xx)//20)==0 and self.verbose: 86 | print(('Bassetti Erskine evaluation %.0f'%(float(ii)/ float(len(xx))*100)+"""%""")) 87 | 88 | for jj in range(len(yy)): 89 | x=xx[ii]; 90 | y=yy[jj]; 91 | Ex_imag,Ey_imag = ImageTerms(x,y,x_aper,y_aper,0,0, n_imag_ellip) 92 | Ex_BE,Ey_BE = BassErsk(x,y,sigmax,sigmay) 93 | Ex[ii,jj] = Ex_BE + Ex_imag 94 | Ey[ii,jj] = Ey_BE + Ey_imag 95 | 96 | YY,XX = np.meshgrid(self.yg, self.xg) 97 | self.rho = tot_charge/(2.*np.pi*sigmax*sigmay)*np.exp(-(XX)**2/(2.*sigmax**2)-(YY)**2/(2.*sigmay**2)) 98 | self.phi = np.zeros((self.Nxg,self.Nyg)) 99 | self.efx = tot_charge * Ex.real 100 | self.efy = tot_charge * Ey.real 101 | 102 | 103 | #@profile 104 | def solve(self, rho = None, flag_verbose = False): 105 | if not self.allow_scatter_and_solve: 106 | raise ValueError('Bassetti_Erskine: nothing to solve!!!!') 107 | 108 | def scatter(self, x_mp, y_mp, nel_mp, charge = -qe, flag_add=False): 109 | if not self.allow_scatter_and_solve: 110 | raise ValueError('Bassetti_Erskine: what do you want to scatter???!!!!') 111 | 112 | 113 | 114 | 115 | def wfun(z): 116 | x=z.real 117 | y=z.imag 118 | wx,wy=errf(x,y) 119 | return wx+1j*wy 120 | 121 | def BassErsk(xin,yin,sigmax,sigmay): 122 | 123 | x=abs(xin); 124 | y=abs(yin); 125 | 126 | 127 | 128 | if sigmax>sigmay: 129 | 130 | S=np.sqrt(2*(sigmax*sigmax-sigmay*sigmay)); 131 | factBE=1/(2*eps0*np.sqrt(np.pi)*S); 132 | etaBE=sigmay/sigmax*x+1j*sigmax/sigmay*y; 133 | zetaBE=x+1j*y; 134 | 135 | val=factBE*(wfun(zetaBE/S)-np.exp( -x*x/(2*sigmax*sigmax)-y*y/(2*sigmay*sigmay))*wfun(etaBE/S) ); 136 | 137 | Ex=abs(val.imag)*np.sign(xin); 138 | Ey=abs(val.real)*np.sign(yin); 139 | 140 | else: 141 | 142 | S=np.sqrt(2*(sigmay*sigmay-sigmax*sigmax)); 143 | factBE=1/(2*eps0*np.sqrt(np.pi)*S); 144 | etaBE=sigmax/sigmay*y+1j*sigmay/sigmax*x; 145 | yetaBE=y+1j*x; 146 | 147 | val=factBE*(wfun(yetaBE/S)-np.exp( -y*y/(2*sigmay*sigmay)-x*x/(2*sigmax*sigmax))*wfun(etaBE/S) ); 148 | 149 | Ey=abs(val.imag)*np.sign(yin); 150 | Ex=abs(val.real)*np.sign(xin); 151 | 152 | return Ex, Ey 153 | 154 | def ImageTerms(x,y,a,b,x0,y0, nimag): 155 | 156 | 157 | eps0=epsilon_0; 158 | 159 | if nimag>0 and abs((a-b)/a)>1e-3: 160 | g=np.sqrt(a*a-b*b) 161 | z=x+1j*y 162 | q=np.arccosh(z/g) 163 | mu=q.real 164 | phi=q.imag 165 | 166 | z0=x0+1j*y0 167 | q0=np.arccosh(z0/g) 168 | mu0=q0.real 169 | phi0=q0.imag 170 | 171 | mu1=0.5*np.log((a+b)/(a-b)) 172 | 173 | Ecpx=0+0j 174 | 175 | 176 | q=np.conj(q) 177 | for nn in range(1,nimag+1): 178 | Ecpx=Ecpx+np.exp(-nn*mu1) * ( (np.cosh(nn*mu0)*np.cos(nn*phi0)) / (np.cosh(nn*mu1)) + 1j * (np.sinh(nn*mu0)*np.sin(nn*phi0)) / (np.sinh(nn*mu1)) )* (np.sinh(nn*q))/(np.sinh(q)) 179 | 180 | 181 | Ecpx=Ecpx/(4*np.pi*eps0)*4/g 182 | Ex=Ecpx.real 183 | Ey=Ecpx.imag 184 | else: 185 | if (x0==0) and (y0==0): 186 | Ex=0. 187 | Ey=0. 188 | else: 189 | print('This case has not been implemented yet') 190 | 191 | return Ex, Ey 192 | 193 | 194 | -------------------------------------------------------------------------------- /FFT_OpenBoundary_SquareGrid.py: -------------------------------------------------------------------------------- 1 | #---------------------------------------------------------------------- 2 | # 3 | # CERN 4 | # 5 | # European Organization for Nuclear Research 6 | # 7 | # 8 | # This file is part of the code: 9 | # 10 | # 11 | # PyPIC Version 2.4.5 12 | # 13 | # 14 | # Author and contact: Giovanni IADAROLA 15 | # BE-ABP Group 16 | # CERN 17 | # CH-1211 GENEVA 23 18 | # SWITZERLAND 19 | # giovanni.iadarola@cern.ch 20 | # 21 | # contact: Giovanni RUMOLO 22 | # BE-ABP Group 23 | # CERN 24 | # CH-1211 GENEVA 23 25 | # SWITZERLAND 26 | # giovanni.rumolo@cern.ch 27 | # 28 | # 29 | # 30 | # Copyright CERN, Geneva 2011 - Copyright and any other 31 | # appropriate legal protection of this computer program and 32 | # associated documentation reserved in all countries of the 33 | # world. 34 | # 35 | # Organizations collaborating with CERN may receive this program 36 | # and documentation freely and without charge. 37 | # 38 | # CERN undertakes no obligation for the maintenance of this 39 | # program, nor responsibility for its correctness, and accepts 40 | # no liability whatsoever resulting from its use. 41 | # 42 | # Program and documentation are provided solely for the use of 43 | # the organization to which they are distributed. 44 | # 45 | # This program may not be copied or otherwise distributed 46 | # without permission. This message must be retained on this and 47 | # any other authorized copies. 48 | # 49 | # The material cannot be sold. CERN should be given credit in 50 | # all references. 51 | #---------------------------------------------------------------------- 52 | 53 | from .FFT_OpenBoundary import FFT_OpenBoundary 54 | 55 | 56 | def FFT_OpenBoundary_SquareGrid(x_aper, y_aper, Dh, fftlib = 'pyfftw'): 57 | return FFT_OpenBoundary(x_aper, y_aper, Dh, fftlib = fftlib) 58 | 59 | 60 | -------------------------------------------------------------------------------- /FFT_PEC_Boundary_SquareGrid.py: -------------------------------------------------------------------------------- 1 | #---------------------------------------------------------------------- 2 | # 3 | # CERN 4 | # 5 | # European Organization for Nuclear Research 6 | # 7 | # 8 | # This file is part of the code: 9 | # 10 | # 11 | # PyPIC Version 2.4.5 12 | # 13 | # 14 | # Author and contact: Giovanni IADAROLA 15 | # BE-ABP Group 16 | # CERN 17 | # CH-1211 GENEVA 23 18 | # SWITZERLAND 19 | # giovanni.iadarola@cern.ch 20 | # 21 | # contact: Giovanni RUMOLO 22 | # BE-ABP Group 23 | # CERN 24 | # CH-1211 GENEVA 23 25 | # SWITZERLAND 26 | # giovanni.rumolo@cern.ch 27 | # 28 | # 29 | # 30 | # Copyright CERN, Geneva 2011 - Copyright and any other 31 | # appropriate legal protection of this computer program and 32 | # associated documentation reserved in all countries of the 33 | # world. 34 | # 35 | # Organizations collaborating with CERN may receive this program 36 | # and documentation freely and without charge. 37 | # 38 | # CERN undertakes no obligation for the maintenance of this 39 | # program, nor responsibility for its correctness, and accepts 40 | # no liability whatsoever resulting from its use. 41 | # 42 | # Program and documentation are provided solely for the use of 43 | # the organization to which they are distributed. 44 | # 45 | # This program may not be copied or otherwise distributed 46 | # without permission. This message must be retained on this and 47 | # any other authorized copies. 48 | # 49 | # The material cannot be sold. CERN should be given credit in 50 | # all references. 51 | #---------------------------------------------------------------------- 52 | 53 | import numpy as np 54 | from .PyPIC_Scatter_Gather import PyPIC_Scatter_Gather 55 | from scipy.constants import e, epsilon_0 56 | import scipy as sp 57 | 58 | na = lambda x:np.array([x]) 59 | 60 | 61 | qe=e 62 | eps0=epsilon_0 63 | 64 | 65 | 66 | 67 | 68 | class FFT_PEC_Boundary_SquareGrid(PyPIC_Scatter_Gather): 69 | #@profile 70 | def __init__(self, x_aper, y_aper, Dh, fftlib='pyfftw'): 71 | 72 | print('Start PIC init.:') 73 | print('FFT, PEC Boundary, Square Grid') 74 | 75 | 76 | self.Dh = Dh 77 | super(FFT_PEC_Boundary_SquareGrid, self).__init__(x_aper, y_aper, self.Dh, self.Dh) 78 | 79 | 80 | 81 | self.i_min = np.min(np.where(self.xg>=-x_aper)[0]) 82 | self.i_max = np.max(np.where(self.xg<=x_aper)[0])+1 83 | self.j_min = np.min(np.where(self.yg>=-y_aper)[0]) 84 | self.j_max = np.max(np.where(self.yg<=y_aper)[0])+1 85 | 86 | self.rho = np.zeros((self.Nxg,self.Nyg)) 87 | self.phi = np.zeros((self.Nxg,self.Nyg)) 88 | self.efx = np.zeros((self.Nxg,self.Nyg)) 89 | self.efy = np.zeros((self.Nxg,self.Nyg)) 90 | 91 | 92 | m, n = self.rho[self.i_min:self.i_max,self.j_min:self.j_max].shape; 93 | 94 | xx = np.arange(1,m+0.5,1); 95 | yy = np.arange(1,n+0.5,1); 96 | 97 | YY, XX = np.meshgrid(yy,xx) 98 | self.green = 4.*eps0*(np.sin(XX/2*np.pi/float(m+1.))**2/self.Dh**2+\ 99 | np.sin(YY/2.*np.pi/float(n+1.))**2/self.Dh**2); 100 | 101 | 102 | # handle border 103 | [xn, yn]=np.meshgrid(self.xg,self.yg) 104 | 105 | xn=xn.T 106 | xn=xn.flatten() 107 | 108 | yn=yn.T 109 | yn=yn.flatten() 110 | #% xn and yn are stored such that the external index is on x 111 | 112 | flag_outside_n=np.logical_or(np.abs(xn)>x_aper,np.abs(yn)>y_aper) 113 | flag_inside_n=~(flag_outside_n) 114 | 115 | 116 | flag_outside_n_mat=np.reshape(flag_outside_n,(self.Nyg,self.Nxg),'F'); 117 | flag_outside_n_mat=flag_outside_n_mat.T 118 | [gx,gy]=np.gradient(np.double(flag_outside_n_mat)); 119 | gradmod=abs(gx)+abs(gy); 120 | flag_border_mat=np.logical_and((gradmod>0), flag_outside_n_mat); 121 | self.flag_border_mat = flag_border_mat 122 | 123 | if fftlib == 'pyfftw': 124 | try: 125 | import pyfftw 126 | rhocut = self.rho[self.i_min:self.i_max,self.j_min:self.j_max] 127 | m, n = rhocut.shape; 128 | tmp = np.zeros((2*m + 2, n)) 129 | self.ffti = pyfftw.builders.fft(tmp.copy(), axis=0) 130 | tmp = np.zeros((m, 2*n + 2)) 131 | self.fftj = pyfftw.builders.fft(tmp.copy(), axis=1) 132 | except ImportError as err: 133 | print('Failed to import pyfftw') 134 | print('Got exception: ', err) 135 | print('Using numpy fft') 136 | self.ffti = lambda xx: np.fft.fft(xx, axis=0) 137 | self.fftj = lambda xx: np.fft.fft(xx, axis=1) 138 | elif fftlib == 'numpy': 139 | self.ffti = lambda xx: np.fft.fft(xx, axis=0) 140 | self.fftj = lambda xx: np.fft.fft(xx, axis=1) 141 | else: 142 | raise ValueError('fftlib not recognized!!!!') 143 | 144 | 145 | def dst2(self, x): 146 | m, n = x.shape; 147 | 148 | #transform along i 149 | tmp = np.zeros((2*m + 2, n)) 150 | tmp[1:m+1, :] = x 151 | tmp=-(self.ffti(tmp).imag) 152 | xtr_i = np.sqrt(2./(m+1.))*tmp[1:m+1, :] 153 | 154 | #transform along j 155 | tmp = np.zeros((m, 2*n + 2)) 156 | tmp[:, 1:n+1] = xtr_i 157 | tmp=-(self.fftj(tmp).imag) 158 | x_bar = np.sqrt(2./(n+1.))*tmp[:, 1:n+1] 159 | 160 | return x_bar 161 | 162 | 163 | #@profile 164 | def solve(self, rho = None, flag_verbose = False): 165 | if rho == None: 166 | rho = self.rho 167 | 168 | rhocut = rho[self.i_min:self.i_max,self.j_min:self.j_max] 169 | 170 | rho_bar = self.dst2(rhocut) 171 | phi_bar = rho_bar/self.green 172 | self.phi[self.i_min:self.i_max,self.j_min:self.j_max] = self.dst2(phi_bar).copy() 173 | 174 | 175 | self.efx[1:self.Nxg-1,:] = self.phi[0:self.Nxg-2,:] - self.phi[2:self.Nxg,:]; #central difference on internal nodes 176 | self.efy[:,1:self.Nyg-1] = self.phi[:,0:self.Nyg-2] - self.phi[:,2:self.Nyg]; #central difference on internal nodes 177 | 178 | self.efx[self.flag_border_mat]=self.efx[self.flag_border_mat]*2; 179 | self.efy[self.flag_border_mat]=self.efy[self.flag_border_mat]*2; 180 | 181 | 182 | self.efy = self.efy/(2*self.Dh) 183 | self.efx = self.efx/(2*self.Dh) 184 | 185 | 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /FPPS/ChangeCoord.cc: -------------------------------------------------------------------------------- 1 | #include "ChangeCoord.h" 2 | #include "FunctionsFPPS.h" 3 | 4 | ChangeCoord::ChangeCoord() 5 | {} 6 | ChangeCoord::~ChangeCoord() {} 7 | 8 | -------------------------------------------------------------------------------- /FPPS/ChangeCoord.h: -------------------------------------------------------------------------------- 1 | #ifndef COORDCHANGE 2 | #define COORDCHANGE 3 | 4 | class ChangeCoord{ 5 | 6 | public: 7 | 8 | ChangeCoord(); 9 | virtual ~ChangeCoord(); 10 | 11 | virtual double f(const double& x) const=0; 12 | virtual double inv_f(const double& x) const=0; 13 | 14 | virtual double der_f(const double& x) const=0; 15 | virtual double der_der_f(const double& x) const=0; 16 | 17 | virtual double getA() const=0; 18 | 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /FPPS/ChangeCoord_Frac.cc: -------------------------------------------------------------------------------- 1 | #include "ChangeCoord_Frac.h" 2 | #include "FunctionsFPPS.h" 3 | #include 4 | 5 | ChangeCoord_Frac::ChangeCoord_Frac(const double& a_): 6 | ChangeCoord(),a(a_) 7 | {} 8 | ChangeCoord_Frac::~ChangeCoord_Frac() {} 9 | 10 | double ChangeCoord_Frac::f(const double& x) const 11 | { 12 | return a*x/(1.0-fabs(x)); 13 | } 14 | double ChangeCoord_Frac::inv_f(const double& x) const 15 | { 16 | return x/(fabs(x)+a); 17 | } 18 | 19 | double ChangeCoord_Frac::der_f(const double& x) const 20 | { 21 | return a/sq2(1.0-fabs(x)); 22 | } 23 | double ChangeCoord_Frac::der_der_f(const double& x) const 24 | { 25 | return 2.0*a/sq2(1.0-fabs(x))/(1.0-fabs(x))*x/fabs(x); 26 | } 27 | 28 | double ChangeCoord_Frac::getA() const 29 | { 30 | return a; 31 | } 32 | -------------------------------------------------------------------------------- /FPPS/ChangeCoord_Frac.h: -------------------------------------------------------------------------------- 1 | #ifndef COORDCHANGEFRAC 2 | #define COORDCHANGEFRAC 3 | 4 | #include "ChangeCoord.h" 5 | 6 | class ChangeCoord_Frac: public ChangeCoord{ 7 | 8 | public: 9 | 10 | ChangeCoord_Frac(const double& a_); 11 | virtual ~ChangeCoord_Frac(); 12 | 13 | double f(const double& x) const; 14 | double inv_f(const double& x) const; 15 | 16 | double der_f(const double& x) const; 17 | double der_der_f(const double& x) const; 18 | 19 | double getA() const; 20 | 21 | private: 22 | 23 | const double a; 24 | 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /FPPS/ChangeCoord_Tanh.cc: -------------------------------------------------------------------------------- 1 | #include "ChangeCoord_Tanh.h" 2 | #include "FunctionsFPPS.h" 3 | #include 4 | 5 | ChangeCoord_Tanh::ChangeCoord_Tanh(const double& a_): 6 | ChangeCoord(), 7 | a(a_) 8 | {} 9 | ChangeCoord_Tanh::~ChangeCoord_Tanh() {} 10 | 11 | double ChangeCoord_Tanh::f(const double& x) const 12 | { 13 | return atanh(x)/a; 14 | } 15 | double ChangeCoord_Tanh::inv_f(const double& x) const 16 | { 17 | return tanh(a*x); 18 | } 19 | 20 | double ChangeCoord_Tanh::der_f(const double& x) const 21 | { 22 | return 1./(1.-a*sq2(x))/a; 23 | } 24 | double ChangeCoord_Tanh::der_der_f(const double& x) const 25 | { 26 | return 2.*x/sq2((1.-sq2(x)))/a; 27 | } 28 | 29 | double ChangeCoord_Tanh::getA() const 30 | { 31 | return a; 32 | } 33 | -------------------------------------------------------------------------------- /FPPS/ChangeCoord_Tanh.h: -------------------------------------------------------------------------------- 1 | #ifndef COORDCHANGETANH 2 | #define COORDCHANGETANH 3 | 4 | #include "ChangeCoord.h" 5 | 6 | class ChangeCoord_Tanh: public ChangeCoord{ 7 | 8 | public: 9 | 10 | ChangeCoord_Tanh(const double& a_); 11 | virtual ~ChangeCoord_Tanh(); 12 | 13 | double f(const double& x) const; 14 | double inv_f(const double& x) const; 15 | 16 | double der_f(const double& x) const; 17 | double der_der_f(const double& x) const; 18 | 19 | double getA() const; 20 | 21 | private: 22 | 23 | const double a; 24 | 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /FPPS/ChargeDistribution.cc: -------------------------------------------------------------------------------- 1 | #include "ChargeDistribution.h" 2 | #include "FunctionsFPPS.h" 3 | #include 4 | 5 | ChargeDistribution::ChargeDistribution(Mesh* m): 6 | mesh(m) 7 | {} 8 | 9 | ChargeDistribution::~ChargeDistribution(){}; 10 | 11 | Mesh* ChargeDistribution::getMesh() { 12 | return mesh; 13 | } 14 | 15 | void ChargeDistribution::fill(PolarBeamRepresentation* polarBeamRepresentation){ 16 | mesh->reset(); 17 | #pragma omp parallel for shared(polarBeamRepresentation) schedule(guided,1000) 18 | for(int i=0; igetSize(); ++i){ 19 | addParticle(polarBeamRepresentation->getRadius(i),polarBeamRepresentation->getAngle(i),polarBeamRepresentation->getCharge(i)); 20 | } 21 | mesh->normalise(); 22 | } 23 | 24 | void ChargeDistribution::addParticle(const double& rReal, const double& theta, const double& charge){ 25 | double r = mesh->computeR(rReal); 26 | int r_ind=mesh->which_R(r); 27 | int theta_ind=mesh->which_Theta(theta); 28 | int theta_next = theta_ind + 1; 29 | if(theta_next==mesh->getPolarSize()) theta_next = 0; 30 | double theta_i=mesh->getTheta(theta_ind); 31 | double aTheta=(theta-theta_i)/mesh->getDeltaTheta(); 32 | 33 | if(r_ind==-1){ 34 | double theta_opp = theta_ind+mesh->getPolarSize()/2; 35 | if(theta_opp>mesh->getPolarSize()) theta_opp -= mesh->getPolarSize(); 36 | double theta_opp_next = theta_opp-1; 37 | if(theta_opp_next == -1) theta_opp_next = mesh->getPolarSize()-1; 38 | double r_i=mesh->getR(0); 39 | double norm = 2.0*sq2(r_i); 40 | double aRadius = (sq2(r_i)+sq2(r))/norm; 41 | double bRadius = (sq2(r_i)-sq2(r))/norm; 42 | mesh->getValue(0,theta_ind)+=(1.0-aTheta)*bRadius*charge; 43 | mesh->getValue(0,theta_next)+=aTheta*bRadius*charge; 44 | mesh->getValue(0,theta_opp)+=(1.0-aTheta)*aRadius*charge; 45 | mesh->getValue(0,theta_opp_next)+=aTheta*aRadius*charge; 46 | }else if(r_indgetRadialSize()-1){ 47 | double r_i=mesh->getR(r_ind); 48 | double r_iplus1=r_i+mesh->getDeltaR(); 49 | double norm = sq2(r_iplus1)-sq2(r_i); // normalisation factor for the itnerpolation + charge 50 | double aRadius = (sq2(r)-sq2(r_i))/norm; 51 | double bRadius = (sq2(r_iplus1)-sq2(r))/norm; 52 | mesh->getValue(r_ind,theta_ind)+=(1.0-aTheta)*bRadius*charge; 53 | mesh->getValue(r_ind,theta_next)+=aTheta*bRadius*charge; 54 | mesh->getValue(r_ind+1,theta_ind)+=(1.0-aTheta)*aRadius*charge; 55 | mesh->getValue(r_ind+1,theta_next)+=aTheta*aRadius*charge; 56 | } 57 | //Ignoring particles outside of the grid 58 | //else { 59 | //mesh->getValue(mesh->getRadialSize()-1,theta_ind)+=charge*aTheta; 60 | //mesh->getValue(mesh->getRadialSize()-1,theta_next)+=charge*(1-aTheta); 61 | //} 62 | } 63 | -------------------------------------------------------------------------------- /FPPS/ChargeDistribution.h: -------------------------------------------------------------------------------- 1 | #ifndef CHARGEDISTRIBUTION 2 | #define CHARGEDISTRIBUTION 3 | 4 | #include "Mesh.h" 5 | #include "PolarBeamRepresentation.h" 6 | 7 | class ChargeDistribution { 8 | public: 9 | ChargeDistribution(Mesh* mesh); 10 | virtual ~ChargeDistribution(); 11 | Mesh* getMesh(); 12 | 13 | void fill(PolarBeamRepresentation* polarBeamRepresentation); 14 | protected: 15 | virtual void addParticle(const double& r,const double& theta, const double& charge); 16 | Mesh* mesh; 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /FPPS/CyFPPS.pyx: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.constants as cst 3 | cimport numpy as np 4 | from libcpp cimport bool 5 | 6 | 7 | cdef extern from "FPPSWrapper.h": 8 | cdef cppclass FPPSWrapper: 9 | void useSourceAsProbe() 10 | void scatter(double* x,double* y,double* nel_part,int n) 11 | void gather(double* x,double* y,double* Ex, double* Ey,int n) 12 | void solve() 13 | 14 | cdef extern from "FPPSWrapper.h": 15 | cdef cppclass FPPSOpenBoundary(FPPSWrapper): 16 | FPPSOpenBoundary(int nTheta, int nR, double a) except + #propagates the exception correctly 17 | 18 | cdef extern from "FPPSWrapper.h": 19 | cdef cppclass FPPSUniform(FPPSWrapper): 20 | FPPSUniform(int nTheta, int nR, double r) except + #propagates the exception correctly 21 | 22 | cdef class PyFPPS: 23 | cdef FPPSWrapper *thisptr # hold a C++ instance which we're wrapping 24 | cdef double particleCharge 25 | def __cinit__(self, int nTheta, int nR, double a,bool useSourceAsProbe=False,solverType = 'Uniform'): 26 | if solverType == 'Uniform': 27 | self.thisptr = new FPPSUniform(nTheta, nR, a) 28 | elif solverType == 'OpenBoundary': 29 | self.thisptr = new FPPSOpenBoundary(nTheta, nR, a) 30 | else: 31 | raise Exception(solverType+' is not a solver type') 32 | if useSourceAsProbe: 33 | self.thisptr.useSourceAsProbe() 34 | 35 | cpdef scatter(self, np.ndarray x, np.ndarray y, np.ndarray nel_part,double charge=cst.e): 36 | self.particleCharge = -charge # PyPIC convention ? 37 | 38 | cdef double* x_data = x.data 39 | cdef double* y_data = y.data 40 | cdef double* nel_part_data = nel_part.data 41 | 42 | self.thisptr.scatter(x_data,y_data,nel_part_data,len(x)) 43 | 44 | cpdef gather(self, np.ndarray x, np.ndarray y): 45 | cdef double* x_data = x.data 46 | cdef double* y_data = y.data 47 | cdef np.ndarray Ex = 0.*x; 48 | cdef np.ndarray Ey = 0.*x; 49 | 50 | cdef double* Ex_data = Ex.data 51 | cdef double* Ey_data = Ey.data 52 | 53 | self.thisptr.gather(x_data, y_data, Ex_data, Ey_data,len(x)) 54 | return Ex*self.particleCharge, Ey*self.particleCharge 55 | 56 | cpdef solve(self): 57 | self.thisptr.solve() 58 | 59 | -------------------------------------------------------------------------------- /FPPS/ElectricFieldSolver.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "ElectricFieldSolver.h" 3 | #include "FunctionsFPPS.h" 4 | #include 5 | #include 6 | #include 7 | 8 | ElectricFieldSolver::ElectricFieldSolver(FastPolarPoissonSolver* s,Mesh* rf,Mesh* pf): 9 | solver(s),radialField(rf),polarField(pf) 10 | {} 11 | 12 | ElectricFieldSolver::~ElectricFieldSolver(){} 13 | 14 | void ElectricFieldSolver::solve() { 15 | 16 | solver->solve(); 17 | // std::stringstream fileNameStream; 18 | // fileNameStream << "Potential_"<< beam <<".csv"; 19 | // std::string fileName = fileNameStream.str(); 20 | // solver->getPotential()->writeToFile(fileName); 21 | #ifdef TIMING 22 | timeval Start; 23 | timeval End; 24 | gettimeofday(&Start,NULL); 25 | #endif 26 | #pragma omp parallel for default(none) collapse(2) schedule(guided,100) 27 | for(int i=0; igetRadialSize(); ++i) 28 | { 29 | for (int j=0; jgetPolarSize(); ++j) 30 | { 31 | //std::cout<<"computing radial field "<setValue(i,j,-solver->getPotential()->getGradR(i,j)); 33 | //std::cout<<"computing polar field "<setValue(i,j,-solver->getPotential()->getGradTheta(i,j)); 35 | //std::cout<<"done "<writeToFile(fileName); 43 | // std::stringstream fileNameStream3; 44 | // fileNameStream3 << "PolarField_"<< beam <<".csv"; 45 | // fileName = fileNameStream3.str(); 46 | // polarField->writeToFile(fileName); 47 | 48 | #ifdef TIMING 49 | gettimeofday(&End,NULL); 50 | double Duration = End.tv_sec-Start.tv_sec+(End.tv_usec-Start.tv_usec)/1E6; 51 | std::cout<<"Time for field computation "<getSize(); ++i) 62 | { 63 | r=radialField->computeR(polarBeamRepresentation->getRadius(i)); 64 | r_ind=radialField->which_R(r); 65 | theta_ind=radialField->which_Theta(polarBeamRepresentation->getAngle(i)); 66 | theta_i=radialField->getTheta(theta_ind); 67 | aTheta=(polarBeamRepresentation->getAngle(i)-theta_i)/radialField->getDeltaTheta(); 68 | theta_next = theta_ind+1; 69 | if(theta_next == radialField->getPolarSize()) theta_next = 0; 70 | 71 | if(r_ind==radialField->getRadialSize()-1){ 72 | Fr=radialField->getValue(r_ind,theta_ind)*(1.0-aTheta)+radialField->getValue(r_ind,theta_next)*aTheta; 73 | Ftheta=polarField->getValue(r_ind,theta_ind)*(1.0-aTheta)+polarField->getValue(r_ind,theta_next)*aTheta; 74 | } else if (r_ind == -1){ 75 | r_i=radialField->getR(0); 76 | theta_opp = theta_ind+radialField->getPolarSize()/2; 77 | if(theta_opp>radialField->getPolarSize()) theta_opp -= radialField->getPolarSize(); 78 | theta_opp_next = theta_opp-1; 79 | if(theta_opp_next == -1) theta_opp_next = radialField->getPolarSize()-1; 80 | 81 | norm=2.0*sq2(r_i); 82 | aRadius = (sq2(r_i)-sq2(r))/norm; 83 | bRadius = (sq2(r_i)+sq2(r))/norm; 84 | 85 | Fr=(aTheta*aRadius)*radialField->getValue(0,theta_opp_next) 86 | +((1.0-aTheta)*aRadius)*radialField->getValue(0,theta_opp) 87 | +(aTheta*bRadius)*radialField->getValue(0,theta_next) 88 | +((1.0-aTheta)*bRadius)*radialField->getValue(0,theta_ind); 89 | 90 | Ftheta=(aTheta*aRadius)*polarField->getValue(0,theta_opp_next) 91 | +((1.0-aTheta)*aRadius)*polarField->getValue(0,theta_opp) 92 | +(aTheta*bRadius)*polarField->getValue(0,theta_next) 93 | +((1.0-aTheta)*bRadius)*polarField->getValue(0,theta_ind); 94 | } else if(r_ind < radialField->getRadialSize()-1){ 95 | r_i=radialField->getR(r_ind); 96 | r_iplus1=r_i+radialField->getDeltaR(); 97 | 98 | norm=(sq2(r_iplus1)-sq2(r_i)); 99 | aRadius = (sq2(r)-sq2(r_i))/norm; 100 | bRadius = (sq2(r_iplus1)-sq2(r))/norm; 101 | 102 | Fr=(aTheta*aRadius)*radialField->getValue(r_ind+1,theta_next) 103 | +((1.0-aTheta)*aRadius)*radialField->getValue(r_ind+1,theta_ind) 104 | +(aTheta*bRadius)*radialField->getValue(r_ind,theta_next) 105 | +((1.0-aTheta)*bRadius)*radialField->getValue(r_ind,theta_ind); 106 | 107 | Ftheta=(aTheta*aRadius)*polarField->getValue(r_ind+1,theta_next) 108 | +((1.0-aTheta)*aRadius)*polarField->getValue(r_ind+1,theta_ind) 109 | +(aTheta*bRadius)*polarField->getValue(r_ind,theta_next) 110 | +((1.0-aTheta)*bRadius)*polarField->getValue(r_ind,theta_ind); 111 | } else{ 112 | continue; //Ignoring particles outside of the grid 113 | } 114 | polarBeamRepresentation->getField(i,x,y,Ex,Ey,Fr,Ftheta); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /FPPS/ElectricFieldSolver.h: -------------------------------------------------------------------------------- 1 | #ifndef ELECTRICFIELD_SOLVER 2 | #define ELECTRICFIELD_SOLVER 3 | 4 | #include "Mesh.h" 5 | #include "FastPolarPoissonSolver.h" 6 | #include "PolarBeamRepresentation.h" 7 | 8 | class ElectricFieldSolver { 9 | public: 10 | ElectricFieldSolver(FastPolarPoissonSolver* s,Mesh* rf,Mesh* pf); 11 | virtual ~ElectricFieldSolver(); 12 | 13 | void solve(); 14 | void getField(PolarBeamRepresentation* polarBeamRepresentation,double* x,double* y,double* Ex,double* Ey) const; 15 | 16 | protected: 17 | FastPolarPoissonSolver* solver; 18 | Mesh* radialField; 19 | Mesh* polarField; 20 | }; 21 | 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /FPPS/FPPSWrapper.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include "FPPSWrapper.h" 7 | 8 | 9 | FPPSWrapper::FPPSWrapper(): 10 | sourceIsProbe(false){} 11 | 12 | FPPSWrapper::~FPPSWrapper() { 13 | delete chargeDistributionMesh; 14 | delete radialField; 15 | delete polarField; 16 | delete chargeDistribution; 17 | delete fastPolarPoissonSolver; 18 | delete electricFieldSolver; 19 | delete sourcePolarBeamRepresentation; 20 | if(!sourceIsProbe){ 21 | delete probePolarBeamRepresentation; 22 | } 23 | } 24 | 25 | void FPPSWrapper::useSourceAsProbe() { 26 | sourceIsProbe = true; 27 | delete probePolarBeamRepresentation; 28 | probePolarBeamRepresentation = sourcePolarBeamRepresentation; 29 | } 30 | 31 | void FPPSWrapper::scatter(double* x,double* y,double* charge,int n) { 32 | sourcePolarBeamRepresentation->update(x,y,charge,n); // compute the polar coordinates of each source particle 33 | chargeDistribution->fill(sourcePolarBeamRepresentation); // scatter the charge on the polar grid 34 | } 35 | void FPPSWrapper::gather(double* x,double* y,double* Ex, double* Ey,int n) { 36 | if(!sourceIsProbe){ 37 | probePolarBeamRepresentation->update(x,y,n); // compute the polar coordinates of each probe particle 38 | } 39 | electricFieldSolver->getField(probePolarBeamRepresentation,x,y,Ex,Ey); // Gather the fields in polar coordinates and project into cartesian coordinates. 40 | } 41 | void FPPSWrapper::solve() { 42 | electricFieldSolver->solve(); 43 | } 44 | 45 | FPPSOpenBoundary::FPPSOpenBoundary(int nTheta, int nR, double a): 46 | FPPSWrapper(){ 47 | g = new ChangeCoord_Frac(a); 48 | chargeDistributionMesh = new NonLinearMesh(nTheta,nR,1.0,g); 49 | radialField = new NonLinearMesh(nTheta,nR,1.0,g); 50 | polarField = new NonLinearMesh(nTheta,nR,1.0,g); 51 | chargeDistribution = new ChargeDistribution(chargeDistributionMesh); 52 | fastPolarPoissonSolver = new FastPolarPoissonSolver(chargeDistribution); 53 | electricFieldSolver = new ElectricFieldSolver(fastPolarPoissonSolver,radialField,polarField); 54 | sourcePolarBeamRepresentation = new PolarBeamRepresentation(0); 55 | probePolarBeamRepresentation = new PolarBeamRepresentation(0); 56 | } 57 | 58 | FPPSOpenBoundary::~FPPSOpenBoundary() { 59 | delete g; 60 | } 61 | 62 | FPPSUniform::FPPSUniform(int nTheta, int nR, double rmax): 63 | FPPSWrapper(){ 64 | chargeDistributionMesh = new Mesh(nTheta,nR,rmax); 65 | radialField = new Mesh(nTheta,nR,rmax); 66 | polarField = new Mesh(nTheta,nR,rmax); 67 | chargeDistribution = new ChargeDistribution(chargeDistributionMesh); 68 | fastPolarPoissonSolver = new FastPolarPoissonSolver(chargeDistribution); 69 | electricFieldSolver = new ElectricFieldSolver(fastPolarPoissonSolver,radialField,polarField); 70 | sourcePolarBeamRepresentation = new PolarBeamRepresentation(0); 71 | probePolarBeamRepresentation = new PolarBeamRepresentation(0); 72 | } 73 | 74 | -------------------------------------------------------------------------------- /FPPS/FPPSWrapper.h: -------------------------------------------------------------------------------- 1 | #ifndef __FPPSTEST 2 | #define __FPPSTEST 3 | 4 | 5 | #include "NonLinearMesh.h" 6 | #include "ChangeCoord_Frac.h" 7 | #include "ChargeDistribution.h" 8 | #include "FastPolarPoissonSolver.h" 9 | #include "ElectricFieldSolver.h" 10 | #include "PolarBeamRepresentation.h" 11 | 12 | class FPPSWrapper{ 13 | public: 14 | FPPSWrapper(); 15 | virtual ~FPPSWrapper(); 16 | void scatter(double* x,double* y,double* charge,int n); 17 | void gather(double* x,double* y,double* Ex, double* Ey,int n); 18 | void solve(); 19 | void useSourceAsProbe(); 20 | 21 | protected: 22 | bool sourceIsProbe; 23 | ChangeCoord_Frac *g; 24 | Mesh *chargeDistributionMesh; 25 | Mesh *radialField; 26 | Mesh *polarField; 27 | ChargeDistribution *chargeDistribution; 28 | FastPolarPoissonSolver *fastPolarPoissonSolver; 29 | ElectricFieldSolver *electricFieldSolver; 30 | PolarBeamRepresentation* sourcePolarBeamRepresentation; 31 | PolarBeamRepresentation* probePolarBeamRepresentation; 32 | }; 33 | 34 | class FPPSUniform : public FPPSWrapper { 35 | public: 36 | FPPSUniform(int nTheta, int nR, double r); 37 | }; 38 | 39 | class FPPSOpenBoundary : public FPPSWrapper { 40 | public: 41 | FPPSOpenBoundary(int nTheta, int nR, double a); 42 | virtual ~FPPSOpenBoundary(); 43 | protected: 44 | ChangeCoord_Frac *g; 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /FPPS/FastPolarPoissonSolver.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "FastPolarPoissonSolver.h" 3 | #include 4 | #include 5 | #include 6 | 7 | FastPolarPoissonSolver::FastPolarPoissonSolver(ChargeDistribution* c): 8 | chargeDistribution(c) 9 | { 10 | fourier = new fftw_complex* [chargeDistribution->getMesh()->getRadialSize()]; 11 | fourierData = new fftw_complex [chargeDistribution->getMesh()->getRadialSize()*chargeDistribution->getMesh()->getPolarSize()]; 12 | plan_direct = new fftw_plan [chargeDistribution->getMesh()->getRadialSize()]; 13 | plan_inverse = new fftw_plan [chargeDistribution->getMesh()->getRadialSize()]; 14 | for(int i=0; igetMesh()->getRadialSize();++i){ 15 | fourier[i]= &(fourierData[i*chargeDistribution->getMesh()->getPolarSize()]); 16 | plan_direct[i] = fftw_plan_dft_r2c_1d(chargeDistribution->getMesh()->getPolarSize(),chargeDistribution->getMesh()->getRingValues(i),fourier[i],FFTW_MEASURE); 17 | plan_inverse[i] = fftw_plan_dft_c2r_1d(chargeDistribution->getMesh()->getPolarSize(),fourier[i],chargeDistribution->getMesh()->getRingValues(i), FFTW_MEASURE); 18 | } 19 | } 20 | 21 | FastPolarPoissonSolver::~FastPolarPoissonSolver(){ 22 | delete fourierData; 23 | delete fourier; 24 | delete plan_direct; 25 | delete plan_inverse; 26 | }; 27 | 28 | Mesh* FastPolarPoissonSolver::getPotential() { 29 | return chargeDistribution->getMesh(); 30 | } 31 | 32 | void FastPolarPoissonSolver::FastPolarPoissonSolver::solve() 33 | { 34 | 35 | #ifdef TIMING 36 | timeval Start; 37 | timeval End; 38 | #endif 39 | 40 | #ifdef TIMING 41 | gettimeofday(&Start,NULL); 42 | #endif 43 | 44 | #pragma omp parallel for schedule(guided,10) 45 | for(int i=0; igetMesh()->getRadialSize(); ++i){ //@fixed r, compute fft u(r,theta) 46 | fftw_execute(plan_direct[i]); 47 | } 48 | // std::stringstream fileNameStreamReal; 49 | // fileNameStreamReal << "FFTReal.csv"; 50 | // std::string fileNameReal = fileNameStreamReal.str(); 51 | // std::stringstream fileNameStreamImag; 52 | // fileNameStreamImag << "FFTImag.csv"; 53 | // std::string fileNameImag = fileNameStreamImag.str(); 54 | // printFourierToFile(fileNameReal,fileNameImag); 55 | 56 | #ifdef TIMING 57 | 58 | gettimeofday(&End,NULL); 59 | double Duration = End.tv_sec-Start.tv_sec+(End.tv_usec-Start.tv_usec)/1E6; 60 | std::cout<<"Time for fftw execute "< lowerDiag = constructLowerDiag(); 64 | const std::vector upperDiag = constructUpperDiag(); 65 | std::vector mainDiag(chargeDistribution->getMesh()->getRadialSize()+1); 66 | int nt=chargeDistribution->getMesh()->getPolarSize()/2+1; 67 | 68 | #ifdef TIMING 69 | gettimeofday(&Start,NULL); 70 | #endif 71 | 72 | #pragma omp parallel for firstprivate(mainDiag) schedule(guided,100) 73 | for(int i=0; igetMesh()->getRadialSize(); ++i) //@fixed r, compute fftback(un(r)) 97 | { 98 | fftw_execute(plan_inverse[i]); 99 | } 100 | #ifdef TIMING 101 | gettimeofday(&End,NULL); 102 | Duration = End.tv_sec-Start.tv_sec+(End.tv_usec-Start.tv_usec)/1E6; 103 | std::cout<<"Time for fftw execute inv "<& a, std::vector& b, const std::vector& c, fftw_complex** d, const int& n) const 109 | { 110 | // Solve the tridiagonal linear system Ax=D , with A a tridiagonal matrice given by its lower diagonal a, main diagonal b, upper diagonal c. 111 | // algorithm from http://www.cfd-online.com/Wiki/Tridiagonal_matrix_algorithm_-_TDMA_(Thomas_algorithm) 112 | 113 | int dim= b.size(); 114 | 115 | 116 | if(((int)a.size())!=dim-1){ 117 | std::cerr<< "Problem in the Thomas Algorithm of the Poisson Solver.\nThe lower diagonal a size does not match with the density given in input.\nDim a= " << a.size() <<" whereas dim d= " << dim<< std::endl; 118 | } 119 | else if(((int)c.size())!=dim-1){ 120 | std::cerr<< "Problem in the Thomas Algorithm of the Poisson Solver.\nThe upper diagonal c size does not match with the density given in input.\nDim c= " << c.size() <<" whereas dim d= " << dim<< std::endl; 121 | } 122 | else if(((int)b.size())!=dim){ 123 | std::cerr<< "Problem in the Thomas Algorithm of the Poisson Solver.\nThe main diagonal b size does not match with the density given in input.\nDim b= " << b.size() <<" whereas dim d= " << dim<< std::endl; 124 | } 125 | else{ 126 | //std::vector tmpb(b); 127 | //std::vector tmpd(d); 128 | 129 | double m =0.0; 130 | double complex BC=0.0; 131 | 132 | for(int j=1; jgetMesh()->getPolarSize()); 136 | m=a[j-1]/b[j-1]; 137 | b[j]=b[j]-m*c[j-1]; 138 | d[j][n]=d[j][n]-(m)*d[j-1][n]; 139 | } 140 | else 141 | { 142 | m=a[j-1]/b[j-1]; 143 | b[j]=b[j]-m*c[j-1]; 144 | BC=BC-(m)*d[j-1][n]; 145 | } 146 | } 147 | 148 | BC=BC/(b[dim-1]); 149 | d[dim-2][n]=(d[dim-2][n]-(c[dim-2])*BC)/(b[dim-2]); 150 | for(int j=dim-3; j>=0; --j) 151 | { 152 | d[j][n]=(d[j][n]-(c[j])*d[j+1][n])/(b[j]); 153 | } 154 | 155 | } 156 | 157 | } 158 | 159 | 160 | //Construction of the linear system 161 | 162 | std::vector FastPolarPoissonSolver::constructLowerDiag() const 163 | { 164 | std::vector v(chargeDistribution->getMesh()->getRadialSize()); 165 | for(int i=0;i<(int)v.size();++i) 166 | { 167 | v[i] = chargeDistribution->getMesh()->getLaplaceLower(i); 168 | } 169 | return v; 170 | } 171 | 172 | void FastPolarPoissonSolver::constructMainDiag(const int& n, std::vector& v) const 173 | { 174 | for(int i=0;i<((int)v.size());++i) 175 | { 176 | v[i] = chargeDistribution->getMesh()->getLaplaceDiag(n,i); 177 | } 178 | } 179 | std::vector FastPolarPoissonSolver::constructUpperDiag() const 180 | { 181 | std::vector v(chargeDistribution->getMesh()->getRadialSize()); 182 | for(int i=0;i<(int)v.size();++i) 183 | { 184 | v[i] = chargeDistribution->getMesh()->getLaplaceUpper(i); 185 | } 186 | return v; 187 | } 188 | 189 | void FastPolarPoissonSolver::printFourierToFile(std::string fileNameReal,std::string fileNameImag) { 190 | 191 | std::ofstream* outReal; 192 | outReal=new std::ofstream; 193 | outReal->open(fileNameReal.c_str()); 194 | std::ofstream* outImag; 195 | outImag=new std::ofstream; 196 | outImag->open(fileNameImag.c_str()); 197 | 198 | for(int i=0; igetMesh()->getRadialSize(); ++i){ 199 | for(int j=0;jgetMesh()->getPolarSize();++j){ 200 | *outReal << creal(fourier[i][j]); 201 | *outImag << cimag(fourier[i][j]); 202 | if(jgetMesh()->getPolarSize()-1){ 203 | *outReal << ","; 204 | *outImag << ","; 205 | } 206 | } 207 | *outReal << std::endl; 208 | *outImag << std::endl; 209 | } 210 | outReal->close(); 211 | outImag->close(); 212 | } 213 | -------------------------------------------------------------------------------- /FPPS/FastPolarPoissonSolver.h: -------------------------------------------------------------------------------- 1 | #ifndef FASTPOLARPOISSONSOLVER 2 | #define FASTPOLARPOISSONSOLVER 3 | 4 | #include 5 | #include 6 | #include 7 | #include "Mesh.h" 8 | #include "ChargeDistribution.h" 9 | 10 | 11 | class FastPolarPoissonSolver{ 12 | public: 13 | FastPolarPoissonSolver(ChargeDistribution* c); 14 | virtual ~FastPolarPoissonSolver(); 15 | 16 | virtual void solve(); 17 | 18 | Mesh* getPotential(); 19 | 20 | protected: 21 | ChargeDistribution* chargeDistribution; 22 | fftw_complex** fourier; 23 | fftw_complex* fourierData; 24 | fftw_plan* plan_direct; 25 | fftw_plan* plan_inverse; 26 | 27 | void ThomasAlgorithm(const std::vector& a, std::vector& b, const std::vector& c, fftw_complex** d, const int& n) const; 28 | virtual std::vector constructLowerDiag() const; 29 | virtual void constructMainDiag(const int& n, std::vector& v) const; 30 | virtual std::vector constructUpperDiag() const; 31 | static double const EPSILON0 = 8.854187817e-12; 32 | 33 | void printFourierToFile(std::string fileNameReal,std::string fileNameImag); 34 | 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /FPPS/FunctionsFPPS.cc: -------------------------------------------------------------------------------- 1 | #include "FunctionsFPPS.h" 2 | 3 | double sq2(const double& x) 4 | { 5 | return x*x; 6 | } 7 | -------------------------------------------------------------------------------- /FPPS/FunctionsFPPS.h: -------------------------------------------------------------------------------- 1 | #ifndef FCT 2 | #define FCT 3 | 4 | double sq2(const double& x); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /FPPS/Mesh.cc: -------------------------------------------------------------------------------- 1 | #include "Mesh.h" 2 | #include "FunctionsFPPS.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | //Constructors 10 | 11 | 12 | Mesh::Mesh(const int& n_j, const int& m_r, const double& r_max): 13 | polarSize(n_j), 14 | radialSize(m_r), 15 | maxRadius(r_max){ 16 | data=new double* [radialSize]; 17 | internalData=new double [radialSize*polarSize]; 18 | for(int i=0;iradialSize or i<-1){ 57 | std::cout<<"From Mesh::getR(int i): i should be 0<=i<="<polarSize or i<0){ 66 | std::cerr<<"From Mesh::getTheta(int i): i should be 0<=i<="<2.0*M_PI){ 78 | std::cerr<<"From Mesh::which_Theta(double j): j has to be in [0.0, 2*pi]. j=" << j << std::endl; 79 | return -1; 80 | } 81 | else return (int)floor(j/getDeltaTheta()); 82 | } 83 | int Mesh::which_R(const double& r) const 84 | { 85 | if(r>maxRadius){ 86 | return maxRadius; 87 | }else if(r<0){ 88 | std::cout<<"Error in Mesh::which_R(double R): R is negative"<0){ 108 | if(y>0)return atan(fabs(y/x)); 109 | else if(y==0.0) return 0.0; 110 | else if(y<0) return 2.0*M_PI-atan(fabs(y/x)); 111 | else{ 112 | std::cerr<<"Problem in Mesh::computeTheta: x>0, y weird. 0.0 returned."<< std::endl; 113 | return 0.0; 114 | } 115 | }else if(x==0.0){ 116 | if(y>0) return M_PI/2.0; 117 | else if(y==0.0){ 118 | std::cerr<<"Problem in Mesh::computeTheta: x=y=0, j not defined. 0.0 returned."<< x << " " <0) return M_PI-atan(fabs(y/x)); 127 | else if(y==0.0) return M_PI; 128 | else if(y<0) return atan(fabs(y/x))+M_PI; 129 | else{ 130 | std::cerr<<"Problem in Mesh::computeTheta: x<0, y weird. 0.0 returned."<< std::endl; 131 | return 0.0; 132 | } 133 | }else{ 134 | std::cerr<<"Problem in Mesh::computeTheta: x weird. 0.0 returned."<0 && iopen(filename.c_str()); 213 | for(int i=0;iclose(); 222 | delete out; 223 | } 224 | 225 | 226 | 227 | -------------------------------------------------------------------------------- /FPPS/Mesh.h: -------------------------------------------------------------------------------- 1 | #ifndef MESH 2 | #define MESH 3 | 4 | #include 5 | 6 | class Mesh{ 7 | public: 8 | Mesh(const int& n_theta, const int& m_r, const double& r_max); 9 | virtual ~Mesh(); 10 | 11 | int getPolarSize() const; 12 | int getRadialSize() const; 13 | int getSize() const; 14 | double getMaxRadius() const; 15 | double getR(const int& i) const; 16 | double getTheta(const int& i) const; 17 | 18 | double getDeltaR() const; 19 | double getDeltaTheta() const; 20 | 21 | virtual double getLaplaceUpper(const int& i) const; 22 | virtual double getLaplaceDiag(const int& n,const int& i) const; 23 | virtual double getLaplaceLower(const int& i) const; 24 | 25 | virtual double getGradR(const int& i, const int& j) const; 26 | virtual double getGradTheta(const int& i, const int& j) const; 27 | 28 | int which_Theta(const double& theta) const; 29 | int which_R(const double& r) const; 30 | 31 | virtual double computeR(const double& r) const; 32 | double computeTheta(const double& x, const double& y) const; 33 | 34 | double& getValue(const int& i,const int& j) const; 35 | double* getRingValues(const int& r) const; 36 | void setValue(const int& i,const int& j, double value); 37 | 38 | void reset(); 39 | virtual void normalise(); 40 | 41 | void writeToFile(std::string filename) const; 42 | 43 | protected: 44 | 45 | int polarSize; 46 | int radialSize; 47 | double maxRadius; 48 | 49 | double** data; 50 | double* internalData; 51 | 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /FPPS/NonLinearMesh.cc: -------------------------------------------------------------------------------- 1 | #include "NonLinearMesh.h" 2 | #include "FunctionsFPPS.h" 3 | #include 4 | #include 5 | 6 | NonLinearMesh::NonLinearMesh(const int& n_theta, const int& m_r, const double& r_max,ChangeCoord* c): 7 | Mesh(n_theta,m_r,r_max),changeCoord(c) 8 | {} 9 | 10 | NonLinearMesh::~NonLinearMesh(){}; 11 | 12 | double NonLinearMesh::computeR(const double& r) const { 13 | return changeCoord->inv_f(Mesh::computeR(r)); 14 | } 15 | 16 | double NonLinearMesh::getLaplaceUpper(const int& i) const { 17 | double der = changeCoord->der_f(getR(i)); 18 | return 1./(sq2(der)*sq2(getDeltaR()))+(1./(changeCoord->f(getR(i))*der)-changeCoord->der_der_f(getR(i))/(sq2(der)*der))/(2.0*getDeltaR()); 19 | } 20 | double NonLinearMesh::getLaplaceDiag(const int& n,const int& i) const { 21 | if(i==getRadialSize()) return 1.0; 22 | else if(i==0) { 23 | double x = getR(0); 24 | double f = changeCoord->f(x); 25 | double der = changeCoord->der_f(x); 26 | return -2./(sq2(der)*sq2(getDeltaR()))-(double)(n*n)/sq2(f)+pow(-1.0,n)*(1.0/(sq2(der)*sq2(getDeltaR()))-(1./(f*der)-changeCoord->der_der_f(x)/(sq2(der)*der))/(2.0*getDeltaR())); 27 | }else return -2./(sq2(changeCoord->der_f(getR(i)))*sq2(getDeltaR()))-(double)(n*n)/sq2(changeCoord->f(getR(i))); 28 | } 29 | double NonLinearMesh::getLaplaceLower(const int& i) const{ 30 | if(i==getRadialSize()-1) return 0.0; 31 | else { 32 | double der = changeCoord->der_f(getR(i+1)); 33 | return 1./(sq2(der)*sq2(getDeltaR()))-(1./(changeCoord->f(getR(i+1))*der)-changeCoord->der_der_f(getR(i+1))/(sq2(der)*der))/(2.0*getDeltaR()); 34 | } 35 | } 36 | 37 | double NonLinearMesh::getGradR(const int& i, const int& j) const { 38 | return Mesh::getGradR(i,j)/changeCoord->der_f(getR(i)); 39 | } 40 | 41 | double NonLinearMesh::getGradTheta(const int& i, const int& j) const { 42 | int jPrev = j-1; 43 | if(jPrev == -1) jPrev = getPolarSize()-1; 44 | int jNext = j+1; 45 | if(jNext == getPolarSize()) jNext = 0; 46 | return (data[i][jNext]-data[i][jPrev])/(2.0*getDeltaTheta()*changeCoord->f(getR(i))); 47 | } 48 | 49 | 50 | // normalise to the area of each cell 51 | void NonLinearMesh::normalise(){ 52 | for(int i=0;if(getR(i))*getDeltaTheta()*changeCoord->der_f(getR(i)); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /FPPS/NonLinearMesh.h: -------------------------------------------------------------------------------- 1 | #ifndef NLMESH 2 | #define NLMESH 3 | 4 | #include "Mesh.h" 5 | #include "ChangeCoord.h" 6 | 7 | class NonLinearMesh : public Mesh { 8 | public: 9 | NonLinearMesh(const int& n_theta, const int& m_r, const double& r_max,ChangeCoord* changeCoord); 10 | virtual ~NonLinearMesh(); 11 | 12 | virtual double computeR(const double& r) const; 13 | 14 | virtual double getLaplaceUpper(const int& i) const; 15 | virtual double getLaplaceDiag(const int& n,const int& i) const; 16 | virtual double getLaplaceLower(const int& i) const; 17 | 18 | virtual double getGradR(const int& i, const int& j) const; 19 | virtual double getGradTheta(const int& i, const int& j) const; 20 | virtual void normalise(); 21 | 22 | protected: 23 | ChangeCoord* changeCoord; 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /FPPS/PolarBeamRepresentation.cc: -------------------------------------------------------------------------------- 1 | #include "PolarBeamRepresentation.h" 2 | #include 3 | #include 4 | 5 | PolarBeamRepresentation::PolarBeamRepresentation(int n): 6 | npart(n) { 7 | radius = new double[npart]; 8 | angle = new double[npart]; 9 | } 10 | PolarBeamRepresentation::~PolarBeamRepresentation() { 11 | delete radius; 12 | delete angle; 13 | } 14 | 15 | double PolarBeamRepresentation::getCharge(int i){ 16 | return charge[i]; 17 | } 18 | double PolarBeamRepresentation::getRadius(int i){ 19 | return radius[i]; 20 | } 21 | double PolarBeamRepresentation::getAngle(int i){ 22 | return angle[i]; 23 | } 24 | int PolarBeamRepresentation::getSize(){ 25 | return npart; 26 | } 27 | 28 | void PolarBeamRepresentation::getField(int i,double* x,double* y,double* Ex,double* Ey,double radialField,double polarField) { 29 | double costheta=x[i]/radius[i]; 30 | double sintheta=y[i]/radius[i]; 31 | Ex[i] += costheta*radialField-sintheta*polarField; 32 | Ey[i] += sintheta*radialField+costheta*polarField; 33 | } 34 | 35 | void PolarBeamRepresentation::update(double* x,double* y,double* sourceCharge, int n) { 36 | if(n!=npart) { 37 | npart = n; 38 | delete radius; 39 | delete angle; 40 | radius = new double[npart]; 41 | angle = new double[npart]; 42 | } 43 | 44 | charge = sourceCharge; 45 | #pragma omp parallel for schedule(guided,1000) 46 | for(int i=0; i=1); 70 | 71 | def impact_point_and_normal(self, x_in, y_in, z_in, x_out, y_out, z_out, resc_fac=0.99, flag_robust=True): 72 | 73 | self.N_mp_impact=self.N_mp_impact+len(x_in) 74 | 75 | a=self.x_aper 76 | b=self.y_aper 77 | 78 | x_insq=x_in*x_in; 79 | y_insq=y_in*y_in; 80 | x_outsq=x_out*x_out; 81 | y_outsq=y_out*y_out; 82 | y_in__y_out=y_in*y_out; 83 | x_in__x_out=x_in*x_out; 84 | 85 | 86 | t0=(a**2*y_insq - a**2*y_in__y_out + \ 87 | sqrt(a**4*b**2*y_insq - 2*a**4*b**2*y_in__y_out \ 88 | + a**4*b**2*y_outsq + \ 89 | a**2*b**4*x_insq - 2*a**2*b**4*x_in__x_out + \ 90 | a**2*b**4*x_outsq - a**2*b**2*x_insq* \ 91 | y_outsq + 2*a**2*b**2*x_in__x_out*y_in__y_out - \ 92 | a**2*b**2*x_outsq*y_insq) + b**2*x_insq - \ 93 | b**2*x_in__x_out)/(a**2*y_insq - \ 94 | 2*a**2*y_in__y_out + a**2*y_outsq + b**2*x_insq - \ 95 | 2*b**2*x_in__x_out + b**2*x_outsq); 96 | 97 | 98 | 99 | # Handle pathological cases 100 | mask_nan = isnan(t0) 101 | if sum(mask_nan)>0: 102 | t0[mask_nan]=0. 103 | if self.flag_verbose_file: 104 | x_nan=x_in[mask_nan] 105 | y_nan=y_in[mask_nan] 106 | fbckt=open('bcktr_errors.txt','a') 107 | for ii_bk in range(len(y_nan)): 108 | fbckt.write('%e\t%e\tnan\n'%(x_nan[ii_bk],y_nan[ii_bk])) 109 | fbckt.close() 110 | 111 | t0=resc_fac*t0; 112 | 113 | t0[t0<1.e-2]=0; 114 | 115 | flag_ident=(((x_in-x_out)*(x_in-x_out)+(y_in-y_out)*(y_in-y_out))/(x_out*x_out+y_out*y_out))<1e-8; 116 | t0[flag_ident]=0; 117 | 118 | 119 | 120 | if sum(abs(t0.imag))>0: 121 | print('imag detected') 122 | raise ValueError('Backtracking: complex t0!!!!') 123 | 124 | x_int=t0*x_out+(1-t0)*x_in; 125 | y_int=t0*y_out+(1-t0)*y_in; 126 | z_int=t0*z_out+(1-t0)*z_in; 127 | 128 | 129 | if flag_robust: 130 | flag_impact=(((x_int/a)**2 + (y_int/b)**2)>1); 131 | 132 | 133 | if flag_impact.any(): 134 | self.N_mp_corrected = self.N_mp_corrected + sum(flag_impact) 135 | ntrials=10 136 | while (sum(flag_impact)>0 and ntrials>0): 137 | t0[flag_impact]=0.9*t0[flag_impact]; 138 | x_int=t0*x_out+(1-t0)*x_in; 139 | y_int=t0*y_out+(1-t0)*y_in; 140 | z_int=t0*z_out+(1-t0)*z_in; 141 | 142 | flag_impact=(((x_int/a)**2 + (y_int/b)**2)>1); 143 | ntrials=ntrials-1 144 | 145 | flag_impact=(((x_int/a)**2 + (y_int/b)**2)>=1); 146 | if sum(flag_impact)>0: 147 | 148 | x_int_pat = x_int[flag_impact] 149 | y_int_pat = y_int[flag_impact] 150 | 151 | if self.flag_verbose_file: 152 | fbckt=open('bcktr_errors.txt','a') 153 | for ii_bk in range(len(x_int_pat)): 154 | fbckt.write('%e\t%e\n'%(x_int_pat[ii_bk],y_int_pat[ii_bk])) 155 | 156 | fbckt.close() 157 | 158 | 159 | x_pr=x_int_pat/a 160 | y_pr=y_int_pat/b 161 | 162 | r_pr=sqrt(x_pr**2+y_pr**2) 163 | 164 | x_pr=0.99*x_pr/r_pr 165 | y_pr=0.99*y_pr/r_pr 166 | 167 | x_int[flag_impact] = x_pr*a 168 | y_int[flag_impact] = y_pr*b 169 | 170 | 171 | 172 | 173 | flag_impact=(((x_int/a)**2 + (y_int/b)**2)>=1); 174 | if sum(flag_impact)>0: 175 | print('err inside') 176 | raise ValueError('Outside after backtracking!!!!') 177 | 178 | 179 | 180 | 181 | 182 | par_cross=arctan2(a*y_int,b*x_int); 183 | 184 | Dx=-a*sin(par_cross); 185 | Dy=b*cos(par_cross); 186 | 187 | Nx=-Dy; 188 | Ny=Dx; 189 | 190 | neg_flag=((Nx*x_int+Ny*y_int)>0); 191 | 192 | Nx[neg_flag]=-Nx[neg_flag]; 193 | Ny[neg_flag]=-Ny[neg_flag]; 194 | 195 | 196 | nor=sqrt(Nx*Nx+Ny*Ny); 197 | 198 | Nx=Nx/nor; 199 | Ny=Ny/nor; 200 | 201 | i_found=None 202 | 203 | return x_int,y_int,z_int,Nx,Ny, i_found 204 | 205 | -------------------------------------------------------------------------------- /GPU/gradient/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyCOMPLETE/PyPIC/2b011d901149fad22a6a0d0d4304034f985aa00a/GPU/gradient/__init__.py -------------------------------------------------------------------------------- /GPU/gradient/gradient.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.constants import e 3 | 4 | import os 5 | where = os.path.dirname(os.path.abspath(__file__)) + '/' 6 | 7 | try: 8 | from pycuda import driver as cuda 9 | from pycuda import gpuarray 10 | from pycuda.compiler import SourceModule 11 | from pycuda.tools import DeviceData 12 | except ImportError: 13 | print('pycuda not found. no gpu capabilities will be available') 14 | 15 | 16 | def make_GPU_gradient(mesh, context): 17 | '''Prepare to compute gradient on the GPU w.r.t. the given mesh. 18 | Return gradient function. 19 | ''' 20 | mx = int(getattr(mesh, 'nx', 1)) 21 | my = int(getattr(mesh, 'ny', 1)) 22 | mz = int(getattr(mesh, 'nz', 1)) 23 | 24 | dxInv = np.array(1./getattr(mesh, 'dx', 1), dtype=np.float64) 25 | dyInv = np.array(1./getattr(mesh, 'dy', 1), dtype=np.float64) 26 | dzInv = np.array(1./getattr(mesh, 'dz', 1), dtype=np.float64) 27 | 28 | sizeof_double = 8 29 | with open(where + 'gradient2.cu') as fdlib: 30 | source = fdlib.read() 31 | module = SourceModule(source) 32 | 33 | mx_ptr = module.get_global("mx")[0] 34 | my_ptr = module.get_global("my")[0] 35 | mz_ptr = module.get_global("mz")[0] 36 | cuda.memcpy_htod(mx_ptr, np.array(mx, dtype=np.int32)) 37 | cuda.memcpy_htod(my_ptr, np.array(my, dtype=np.int32)) 38 | cuda.memcpy_htod(mz_ptr, np.array(mz, dtype=np.int32)) 39 | 40 | dxInv_ptr = module.get_global("dxInv")[0] 41 | dyInv_ptr = module.get_global("dyInv")[0] 42 | dzInv_ptr = module.get_global("dzInv")[0] 43 | cuda.memcpy_htod(dxInv_ptr, dxInv) 44 | cuda.memcpy_htod(dyInv_ptr, dyInv) 45 | cuda.memcpy_htod(dzInv_ptr, dzInv) 46 | 47 | deriv_x = module.get_function("gradient_x") 48 | deriv_y = module.get_function("gradient_y") 49 | deriv_z = module.get_function("gradient_z") 50 | 51 | block, grid = mesh.get_domain_decomposition(DeviceData().max_threads) 52 | 53 | d_deriv_x = gpuarray.empty(shape=(1, mesh.n_nodes), dtype=np.float64) 54 | d_deriv_y = gpuarray.empty_like(d_deriv_x) 55 | d_deriv_z = gpuarray.empty_like(d_deriv_x) 56 | 57 | def _gradient(scalar_values): 58 | '''Calculate three-dimensional gradient for GPUArray 59 | scalar_values. 60 | ''' 61 | deriv_x(scalar_values, d_deriv_x, block=block, grid=grid) 62 | deriv_y(scalar_values, d_deriv_y, block=block, grid=grid) 63 | deriv_z(scalar_values, d_deriv_z, block=block, grid=grid) 64 | context.synchronize() 65 | 66 | return (d_deriv_x, d_deriv_y, d_deriv_z)[:mesh.dimension] 67 | return _gradient 68 | 69 | def numpy_gradient(mesh): 70 | ''' Return a gradient function''' 71 | def _gradient(scalar_values): 72 | '''Return the gradient of the scalar_values on the mesh''' 73 | D = np.gradient(-scalar_values.reshape(mesh.shape), 74 | *(list(reversed(mesh.distances)))) 75 | return list(reversed(D)) 76 | return _gradient 77 | 78 | -------------------------------------------------------------------------------- /GPU/gradient/gradient2.cu: -------------------------------------------------------------------------------- 1 | // 2nd order FD scheme for gradient with uniform mesh spacing 2 | #include 3 | 4 | __constant__ int mx, my, mz; 5 | __constant__ double dxInv, dyInv, dzInv; 6 | 7 | __global__ void gradient_x(double* f, double* df) { 8 | //f: vector of function values 9 | //df: vector of derivatives (output) 10 | 11 | int i = blockIdx.x*blockDim.x + threadIdx.x; 12 | int j = blockIdx.y*blockDim.y + threadIdx.y; 13 | int k = blockIdx.z; 14 | 15 | int globalIdx = k * mx * my + j * mx + i; 16 | if (i > 0 && i < mx-1) { 17 | df[globalIdx] = (-0.5*f[globalIdx-1] + 0.5*f[globalIdx+1])*dxInv; 18 | } else if (i == 0 && mx > 1) { 19 | df[globalIdx] = (-f[globalIdx] + f[globalIdx+1])*dxInv; 20 | } else if (i == mx-1 && mx > 1) { 21 | df[globalIdx] = (-f[globalIdx-1] + f[globalIdx])*dxInv; 22 | } 23 | } 24 | 25 | __global__ void gradient_y(double* f, double* df) { 26 | //f: vector of function values 27 | //df: vector of derivatives (output) 28 | 29 | int i = blockIdx.x*blockDim.x + threadIdx.x; 30 | int j = blockIdx.y*blockDim.y + threadIdx.y; 31 | int k = blockIdx.z; 32 | 33 | int globalIdx = k * mx * my + j * mx + i; 34 | if (j > 0 && j < my-1) { 35 | df[globalIdx] = (-0.5*f[globalIdx-mx] + 0.5*f[globalIdx+mx])*dyInv; 36 | } else if (j == 0 && my > 1) { 37 | df[globalIdx] = (-f[globalIdx] + f[globalIdx+mx])*dyInv; 38 | } else if (j == my-1 && my > 1) { 39 | df[globalIdx] = (-f[globalIdx-mx] + f[globalIdx])*dyInv; 40 | } 41 | } 42 | __global__ void gradient_z(double* f, double* df) { 43 | //f: vector of function values 44 | //df: vector of derivatives (output) 45 | 46 | int i = blockIdx.x*blockDim.x + threadIdx.x; 47 | int j = blockIdx.y*blockDim.y + threadIdx.y; 48 | int k = blockIdx.z; 49 | 50 | int globalIdx = k * mx * my + j * mx + i; 51 | if (k > 0 && k < mz-1) { 52 | df[globalIdx] = (-0.5*f[globalIdx-mx*my] + 0.5*f[globalIdx+mx*my])*dzInv; 53 | } else if (k == 0 && mz > 1) { 54 | df[globalIdx] = (-f[globalIdx] + f[globalIdx+mx*my])*dzInv; 55 | } else if (k == mz-1 && mz > 1) { 56 | df[globalIdx] = (-f[globalIdx-mx*my] + f[globalIdx])*dzInv; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /GPU/m2p/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyCOMPLETE/PyPIC/2b011d901149fad22a6a0d0d4304034f985aa00a/GPU/m2p/__init__.py -------------------------------------------------------------------------------- /GPU/m2p/interp_field_for.f: -------------------------------------------------------------------------------- 1 | *----------------------------------------------------------------------* 2 | * COMPILE USING 3 | * f2py -m int_field_for -c interp_field_for.f 4 | 5 | subroutine int_field(N_mp,xn,yn, bias_x,bias_y, dx,dy,efx, efy, 6 | + Nxg, Nyg, Ex_n, Ey_n) 7 | Cf2py intent(in) N_mp 8 | Cf2py intent(in) xn 9 | Cf2py intent(in) yn 10 | Cf2py intent(in) bias_x 11 | Cf2py intent(in) bias_y 12 | Cf2py intent(in) dx 13 | Cf2py intent(in) dy 14 | Cf2py intent(in) efx 15 | Cf2py intent(in) efy 16 | Cf2py intent(in) Nxg 17 | Cf2py intent(in) Nyg 18 | Cf2py intent(out) Ex_n 19 | Cf2py intent(out) Ey_n 20 | 21 | 22 | implicit none 23 | integer N_mp 24 | real*8 xn(N_mp), yn(N_mp) 25 | real*8 bias_x, bias_y, dx, dy 26 | integer Nxg,Nyg 27 | real*8 efx(Nxg, Nyg), efy(Nxg, Nyg) 28 | integer p 29 | real*8 fi, fj, hx, hy 30 | integer i, j 31 | real*8 Ex_n(N_mp), Ey_n(N_mp) 32 | 33 | 34 | 35 | do p=1,N_mp 36 | fi = 1+(xn(p)-bias_x)/dx; !i index of particle's cell 37 | i = int(fi); 38 | hx = fi-dble(i); !fractional x position in cell 39 | 40 | 41 | fj = 1+(yn(p)-bias_y)/dy; !j index of particle' cell(C-like!!!!) 42 | j = int(fj); 43 | hy = fj-dble(j); !fractional y position in cell 44 | 45 | 46 | !gather electric field 47 | if (i>0 .and. j>0 .and. i0 .and. j>0 .and. i slow) for the mesh to particles functions 3 | used in PyPIC 4 | @author Stefan Hegglin, Adrian Oeftiger 5 | ''' 6 | import numpy as np 7 | 8 | def mesh_to_particles_CPU_3d(mesh, mesh_quantity, indices, weights): 9 | """CPU kernel for 3d mesh to particles quantity interpolation""" 10 | ip, jp, kp = indices 11 | stridex = mesh.nx 12 | stridey = mesh.ny 13 | mq = np.ravel(mesh_quantity) 14 | 15 | @np.vectorize 16 | def check_outside(ip, jp, kp): 17 | outside_idx = (jp < 0 or jp >= mesh.nx - 1 or 18 | ip < 0 or ip >= mesh.ny - 1 or 19 | kp < 0 or kp >= mesh.nz - 1) 20 | return outside_idx 21 | outside_idx = check_outside(ip, jp, kp) 22 | inside_idx = ~outside_idx 23 | ip, jp, kp = ip[inside_idx], jp[inside_idx], kp[inside_idx] 24 | weights = [w[inside_idx] for w in weights] 25 | 26 | particles_quantity = np.empty(len(indices[0]), dtype=mesh_quantity.dtype) 27 | particles_quantity[inside_idx] = ( 28 | mq[jp + stridex*ip + stridex*stridey*kp ] * weights[0] 29 | + mq[jp + stridex*(ip+1) + stridex*stridey*kp ] * weights[1] 30 | + mq[jp+1 + stridex*ip + stridex*stridey*kp ] * weights[2] 31 | + mq[jp+1 + stridex*(ip+1) + stridex*stridey*kp ] * weights[3] 32 | + mq[jp + stridex*ip + stridex*stridey*(kp+1)] * weights[4] 33 | + mq[jp + stridex*(ip+1) + stridex*stridey*(kp+1)] * weights[5] 34 | + mq[jp+1 + stridex*ip + stridex*stridey*(kp+1)] * weights[6] 35 | + mq[jp+1 + stridex*(ip+1) + stridex*stridey*(kp+1)] * weights[7]) 36 | 37 | particles_quantity[outside_idx] = 0 38 | return particles_quantity 39 | 40 | def mesh_to_particles_CPU_2d(mesh, mesh_quantity, indices, weights): 41 | """CPU kernel for 3d mesh to particles quantity interpolation""" 42 | ip, jp = indices 43 | stridex = mesh.nx 44 | mesh_quantity = np.ravel(mesh_quantity) 45 | 46 | @np.vectorize 47 | def check_outside(ip, jp): 48 | outside_idx = (jp < 0 or jp >= mesh.nx - 1 or 49 | ip < 0 or ip >= mesh.ny - 1) 50 | return outside_idx 51 | outside_idx = check_outside(ip, jp) 52 | inside_idx = ~outside_idx 53 | ip, jp = ip[inside_idx], jp[inside_idx] 54 | weights = [w[inside_idx] for w in weights] 55 | 56 | particles_quantity = np.empty(len(indices[0]), dtype=mesh_quantity.dtype) 57 | particles_quantity[inside_idx] = ( 58 | mesh_quantity[jp + stridex*ip ] * weights[0] 59 | + mesh_quantity[jp + stridex*(ip+1)] * weights[1] 60 | + mesh_quantity[jp+1 + stridex*ip ] * weights[2] 61 | + mesh_quantity[jp+1 + stridex*(ip+1)] * weights[3]) 62 | 63 | particles_quantity[outside_idx] = 0 64 | return particles_quantity 65 | -------------------------------------------------------------------------------- /GPU/m2p/m2p_kernels.cu: -------------------------------------------------------------------------------- 1 | /* 2 | GPU Kernels for the mesh to particles functions 3 | @author: Stefan Hegglin, Adrian Oeftiger 4 | */ 5 | 6 | extern "C" { 7 | 8 | __global__ void mesh_to_particles_2d( 9 | int nparticles, 10 | double* particles_quantity, double *mesh_quantity, 11 | const int nx, const int ny, 12 | double *wij, double *wi1j, double *wij1, double *wi1j1, 13 | int *i, int *j) 14 | { 15 | int pidx = blockIdx.x * blockDim.x * blockDim.y + threadIdx.y* blockDim.x + threadIdx.x; 16 | int ix = i[pidx]; 17 | int jx = j[pidx]; 18 | 19 | if (pidx < nparticles) { 20 | if (jx >= 0 && jx < nx - 1 && ix >= 0 && ix < ny - 1) 21 | { 22 | particles_quantity[pidx] = ( wij[pidx] * mesh_quantity[jx + ix*nx] 23 | + wij1[pidx] * mesh_quantity[jx+1 + ix*nx] 24 | + wi1j[pidx] * mesh_quantity[jx+ + (ix+1)*nx] 25 | + wi1j1[pidx] * mesh_quantity[jx+1 + (ix+1)*nx]); 26 | } else { 27 | particles_quantity[pidx] = 0; 28 | } 29 | } 30 | } 31 | 32 | __global__ void field_to_particles_2d( 33 | int nparticles, 34 | double* forcex, double* forcey, double* fieldx, double* fieldy, 35 | const int nx, const int ny, 36 | double *wij, double *wi1j, double *wij1, double *wi1j1, int *i, int *j) 37 | { 38 | int pidx = blockIdx.x * blockDim.x * blockDim.y + threadIdx.y* blockDim.x + threadIdx.x; 39 | int jx = j[pidx]; 40 | int ix = i[pidx]; 41 | if (pidx < nparticles) { 42 | if (jx >= 0 && jx < nx - 1 && ix >= 0 && ix < ny - 1) 43 | { 44 | forcex[pidx] = ( wij[pidx] * fieldx[jx + ix*nx] 45 | + wij1[pidx] * fieldx[jx+1 + ix*nx] 46 | + wi1j[pidx] * fieldx[jx + (ix+1)*nx] 47 | + wi1j1[pidx] *fieldx[jx+1 + (ix+1)*nx]); 48 | forcey[pidx] = ( wij[pidx] * fieldy[jx + ix*nx] 49 | + wij1[pidx] * fieldy[jx+1 + ix*nx] 50 | + wi1j[pidx] * fieldy[jx + (ix+1)*nx] 51 | + wi1j1[pidx] *fieldy[jx+1 + (ix+1)*nx]); 52 | } else { 53 | forcex[pidx] = 0; 54 | forcey[pidx] = 0; 55 | } 56 | } 57 | } 58 | 59 | __global__ void field_to_particles_3d( 60 | int nparticles, 61 | double* forcex, double* forcey, double* forcez, 62 | double* fieldx, double* fieldy, double* fieldz, 63 | const int nx, const int ny, const int nz, 64 | double *wijk, double *wi1jk, double *wij1k, double *wi1j1k, 65 | double *wijk1, double *wi1jk1, double* wij1k1, double* wi1j1k1, 66 | int *i, int *j, int* k) 67 | { 68 | int pidx = blockIdx.x * blockDim.x * blockDim.y + threadIdx.y* blockDim.x + threadIdx.x; 69 | int ix = i[pidx]; 70 | int jx = j[pidx]; 71 | int kx = k[pidx]; 72 | if (pidx < nparticles) { 73 | if (jx >= 0 && jx < nx - 1 && ix >= 0 && ix < ny - 1 && kx >= 0 && kx < nz - 1) 74 | { 75 | forcex[pidx] = ( wijk[pidx] * fieldx[jx + ix*nx + kx*nx*ny] 76 | + wij1k[pidx] * fieldx[jx+1 + ix*nx + kx*nx*ny] 77 | + wi1jk[pidx] * fieldx[jx+ + (ix+1)*nx + kx*nx*ny] 78 | + wi1j1k[pidx] * fieldx[jx+1 + (ix+1)*nx + kx*nx*ny] 79 | + wijk1[pidx] * fieldx[jx + ix*nx + (kx+1)*nx*ny] 80 | + wij1k1[pidx] * fieldx[jx+1 + ix*nx + (kx+1)*nx*ny] 81 | + wi1jk1[pidx] * fieldx[jx+ + (ix+1)*nx + (kx+1)*nx*ny] 82 | + wi1j1k1[pidx]* fieldx[jx+1 + (ix+1)*nx + (kx+1)*nx*ny]); 83 | 84 | forcey[pidx] = ( wijk[pidx] * fieldy[jx + ix*nx + kx*nx*ny] 85 | + wij1k[pidx] * fieldy[jx+1 + ix*nx + kx*nx*ny] 86 | + wi1jk[pidx] * fieldy[jx+ + (ix+1)*nx + kx*nx*ny] 87 | + wi1j1k[pidx] * fieldy[jx+1 + (ix+1)*nx + kx*nx*ny] 88 | + wijk1[pidx] * fieldy[jx + ix*nx + (kx+1)*nx*ny] 89 | + wij1k1[pidx] * fieldy[jx+1 + ix*nx + (kx+1)*nx*ny] 90 | + wi1jk1[pidx] * fieldy[jx+ + (ix+1)*nx + (kx+1)*nx*ny] 91 | + wi1j1k1[pidx]* fieldy[jx+1 + (ix+1)*nx + (kx+1)*nx*ny]); 92 | 93 | forcez[pidx] = ( wijk[pidx] * fieldz[jx + ix*nx + kx*nx*ny] 94 | + wij1k[pidx] * fieldz[jx+1 + ix*nx + kx*nx*ny] 95 | + wi1jk[pidx] * fieldz[jx+ + (ix+1)*nx + kx*nx*ny] 96 | + wi1j1k[pidx] * fieldz[jx+1 + (ix+1)*nx + kx*nx*ny] 97 | + wijk1[pidx] * fieldz[jx + ix*nx + (kx+1)*nx*ny] 98 | + wij1k1[pidx] * fieldz[jx+1 + ix*nx + (kx+1)*nx*ny] 99 | + wi1jk1[pidx] * fieldz[jx+ + (ix+1)*nx + (kx+1)*nx*ny] 100 | + wi1j1k1[pidx]* fieldz[jx+1 + (ix+1)*nx + (kx+1)*nx*ny]); 101 | } else { 102 | forcex[pidx] = 0; 103 | forcey[pidx] = 0; 104 | forcez[pidx] = 0; 105 | } 106 | } 107 | } 108 | 109 | __global__ void mesh_to_particles_3d( 110 | int nparticles, 111 | double* particles_quantity, double *mesh_quantity, 112 | const int nx, const int ny, const int nz, 113 | double *wijk, double *wi1jk, double *wij1k, double *wi1j1k, 114 | double *wijk1, double *wi1jk1, double* wij1k1, double* wi1j1k1, 115 | int *i, int *j, int* k) 116 | { 117 | int pidx = blockIdx.x * blockDim.x * blockDim.y + threadIdx.y* blockDim.x + threadIdx.x; 118 | int ix = i[pidx]; 119 | int jx = j[pidx]; 120 | int kx = k[pidx]; 121 | if (pidx < nparticles) { 122 | if (jx >= 0 && jx < nx - 1 && ix >= 0 && ix < ny - 1 && kx >= 0 && kx < nz - 1) 123 | { 124 | particles_quantity[pidx] = ( wijk[pidx] * mesh_quantity[jx + ix*nx + kx*nx*ny] 125 | + wij1k[pidx] * mesh_quantity[jx+1 + ix*nx + kx*nx*ny] 126 | + wi1jk[pidx] * mesh_quantity[jx+ + (ix+1)*nx + kx*nx*ny] 127 | + wi1j1k[pidx] * mesh_quantity[jx+1 + (ix+1)*nx + kx*nx*ny] 128 | + wijk1[pidx] * mesh_quantity[jx + ix*nx + (kx+1)*nx*ny] 129 | + wij1k1[pidx] * mesh_quantity[jx+1 + ix*nx + (kx+1)*nx*ny] 130 | + wi1jk1[pidx] * mesh_quantity[jx+ + (ix+1)*nx + (kx+1)*nx*ny] 131 | + wi1j1k1[pidx]* mesh_quantity[jx+1 + (ix+1)*nx + (kx+1)*nx*ny]); 132 | } else { 133 | particles_quantity[pidx] = 0; 134 | } 135 | } 136 | } 137 | 138 | } /* end extern C */ 139 | -------------------------------------------------------------------------------- /GPU/meshing/__init__.py: -------------------------------------------------------------------------------- 1 | from .meshes import ( 2 | UniformMesh1D, RectMesh1D, RectMesh2D, 3 | SlicingMesh25D, RectMesh3D) 4 | -------------------------------------------------------------------------------- /GPU/p2m/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyCOMPLETE/PyPIC/2b011d901149fad22a6a0d0d4304034f985aa00a/GPU/p2m/__init__.py -------------------------------------------------------------------------------- /GPU/p2m/compute_rho.f: -------------------------------------------------------------------------------- 1 | *----------------------------------------------------------------------* 2 | * COMPILE USING 3 | * f2py -m rhocompute -c compute_rho.f 4 | 5 | subroutine compute_sc_rho(N_mp,x_mp, y_mp,nel_mp, bias_x, 6 | + bias_y, Dh, Nxg, Nyg,rho) 7 | Cf2py intent(in) N_mp 8 | Cf2py intent(in) x_mp 9 | Cf2py intent(in) y_mp 10 | Cf2py intent(in) nel_mp 11 | Cf2py intent(in) bias_x 12 | Cf2py intent(in) bias_y 13 | Cf2py intent(in) Dh 14 | Cf2py intent(in) Nxg 15 | Cf2py intent(in) Nyg 16 | Cf2py intent(out) rho 17 | implicit none 18 | integer N_mp 19 | real*8 x_mp(N_mp), y_mp(N_mp), nel_mp(N_mp) 20 | real*8 bias_x, bias_y, Dh 21 | integer Nxg, Nyg 22 | real*8 rho(Nxg, Nyg) 23 | integer p 24 | real*8 nel_mp_curr, fi, fj, hx, hy 25 | integer i, j 26 | 27 | !rho=0d0; 28 | do j=1,Nyg 29 | do i=1,Nxg 30 | rho(i,j)=0.0 31 | end do 32 | end do 33 | !write(*,*) 'ciao fortran' 34 | 35 | do p=1,N_mp 36 | !loop over particles 37 | 38 | fi = 1+(x_mp(p)-bias_x)/Dh; !real i index of particle's cell 39 | i = int(fi); !integral part 40 | hx = fi-dble(i); !the remainder 41 | 42 | 43 | fj = 1+(y_mp(p)-bias_y)/Dh; !real j index of particle's cell (C-like indexing) 44 | j = int(fj); !integral part 45 | hy = fj-dble(j); !the remainder 46 | 47 | nel_mp_curr=nel_mp(p); 48 | 49 | if (i>0 .and. j>0 .and. i slow) for the particles to mesh functions 3 | used in PyPIC 4 | @author Stefan Hegglin, Adrian Oeftiger 5 | ''' 6 | import numpy as np 7 | 8 | def particles_to_mesh_CPU_3d(mesh, n_macroparticles, mesh_indices, weights): 9 | """CPU kernel for 3d mesh to particles interpolation 10 | Port to Cython 11 | """ 12 | mesh_density = np.zeros(mesh.n_nodes, dtype=np.float64) 13 | stridex = mesh.nx 14 | stridey = mesh.ny 15 | for p in range(n_macroparticles): 16 | ip = mesh_indices[0][p] 17 | jp = mesh_indices[1][p] 18 | kp = mesh_indices[2][p] 19 | if (jp < 0 or jp >= mesh.nx - 1 or 20 | ip < 0 or ip >= mesh.ny - 1 or 21 | kp < 0 or kp >= mesh.nz - 1): 22 | continue 23 | mesh_density [jp + stridex*ip + stridex*stridey*kp ] += weights[0][p] 24 | mesh_density [jp + stridex*(ip+1) + stridex*stridey*kp ] += weights[1][p] 25 | mesh_density [jp+1 + stridex*ip + stridex*stridey*kp ] += weights[2][p] 26 | mesh_density [jp+1 + stridex*(ip+1) + stridex*stridey*kp ] += weights[3][p] 27 | mesh_density [jp + stridex*ip + stridex*stridey*(kp+1)] += weights[4][p] 28 | mesh_density [jp + stridex*(ip+1) + stridex*stridey*(kp+1)] += weights[5][p] 29 | mesh_density [jp+1 + stridex*ip + stridex*stridey*(kp+1)] += weights[6][p] 30 | mesh_density [jp+1 + stridex*(ip+1) + stridex*stridey*(kp+1)] += weights[7][p] 31 | mesh_density = mesh_density.reshape(mesh.shape) 32 | return mesh_density 33 | 34 | 35 | def particles_to_mesh_CPU_2d(mesh, n_macroparticles, mesh_indices, weights): 36 | """CPU kernel for 3d mesh to particles interpolation 37 | """ 38 | mesh_density = np.zeros(mesh.n_nodes, dtype=np.float64) 39 | stridex = mesh.nx 40 | for p in range(n_macroparticles): 41 | ip = mesh_indices[0][p] 42 | jp = mesh_indices[1][p] 43 | if (jp < 0 or jp >= mesh.nx - 1 or 44 | ip < 0 or ip >= mesh.ny - 1): 45 | continue 46 | mesh_density [jp + stridex*ip ] += weights[0][p] 47 | mesh_density [jp + stridex*(ip+1)] += weights[1][p] 48 | mesh_density [jp+1 + stridex*ip ] += weights[2][p] 49 | mesh_density [jp+1 + stridex*(ip+1)] += weights[3][p] 50 | mesh_density = mesh_density.reshape(mesh.shape) 51 | return mesh_density 52 | -------------------------------------------------------------------------------- /GPU/poisson_solver/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyCOMPLETE/PyPIC/2b011d901149fad22a6a0d0d4304034f985aa00a/GPU/poisson_solver/__init__.py -------------------------------------------------------------------------------- /GPU/poisson_solver/poisson_solver.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Abstract base class for poisson solvers 3 | @author Stefan Hegglin, Adrian Oeftiger 4 | ''' 5 | 6 | from abc import ABCMeta, abstractmethod 7 | 8 | 9 | class PoissonSolver(object, metaclass=ABCMeta): 10 | '''PoissonSolver instances are prepared for a fixed parameter set 11 | (among others a certain mesh). Given a charge distribution rho on this mesh, 12 | a PoissonSolver solves the corresponding discrete Poisson equation 13 | for a potential phi: 14 | -divgrad phi = rho / epsilon_0 15 | ''' 16 | @abstractmethod 17 | def poisson_solve(self, rho): 18 | '''Solve -divgrad phi = rho / epsilon_0 for the potential phi, 19 | given as input the charge distribution rho on the mesh. 20 | ''' 21 | pass 22 | -------------------------------------------------------------------------------- /GPU/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import numpy as np 3 | import re, os, sys, subprocess 4 | import numpy as np 5 | from numpy.distutils.core import setup, Extension 6 | 7 | args = sys.argv[1:] 8 | # Make a `cleanall` rule to get rid of intermediate and library files 9 | if "cleanall" in args: 10 | print ("Deleting shared libraries.") 11 | # Just in case the build directory was created by accident, 12 | # note that shell=True should be OK here because the command is constant. 13 | subprocess.Popen("rm -rf build", shell=True, executable="/bin/bash") 14 | subprocess.Popen("rm -rf *.so.dSYM", shell=True, executable="/bin/bash") 15 | subprocess.Popen("find ./ -name *.so | xargs rm", shell=True) 16 | 17 | # Now do a normal clean 18 | sys.argv[1] = "clean" 19 | exit(1) 20 | 21 | 22 | # We want to always use build_ext --inplace 23 | if args.count("build_ext") > 0 and args.count("--inplace") == 0: 24 | sys.argv.insert(sys.argv.index("build_ext") + 1, "--inplace") 25 | 26 | verstr = 1.1 27 | 28 | setup( 29 | name='PyPIC', 30 | version=verstr, 31 | description='PyPIC: Particle in Cell codes', 32 | url='http://github.com/PyCOMPLETE/PyPIC', 33 | packages=['PyPIC'], 34 | install_requires=[ 35 | 'numpy', 36 | 'scipy', 37 | 'cython', 38 | ], 39 | ext_modules = [ 40 | Extension('rhocompute', ['p2m/compute_rho.f']), 41 | Extension('int_field_for', ['m2p/interp_field_for.f']), 42 | Extension('int_field_for_border', ['m2p/interp_field_for_with_border.f']), 43 | Extension('vectsum', ['vectsum.f']), 44 | ] 45 | ) 46 | -------------------------------------------------------------------------------- /GPU/test/000_test_round_chamber.py: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.path.append('../') 3 | from backwards_compatibility_1_03 import * 4 | import FiniteDifferences_ShortleyWeller_SquareGrid as PIC_FDSW 5 | import FiniteDifferences_Staircase_SquareGrid as PIC_FD 6 | import FFT_OpenBoundary_SquareGrid as PIC_FFT 7 | import geom_impact_ellip as ell 8 | from scipy import rand 9 | import numpy as np 10 | 11 | R_cham = 1e-1 12 | R_charge = 4e-2 13 | N_part_gen = 100000 14 | Dh = 1e-3 15 | 16 | from scipy.constants import e, epsilon_0 17 | 18 | qe = e 19 | eps0 = epsilon_0 20 | 21 | 22 | chamber = ell.ellip_cham_geom_object(x_aper = R_cham, y_aper = R_cham) 23 | 24 | picFD = PIC_FD.FiniteDifferences_Staircase_SquareGrid(chamb = chamber, Dh = Dh) 25 | picFDSW = PIC_FDSW.FiniteDifferences_ShortleyWeller_SquareGrid(chamb = chamber, Dh = Dh) 26 | picFFT = PIC_FFT.FFT_OpenBoundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh, fftlib='pyfftw') 27 | 28 | # generate particles 29 | x_part = R_charge*(2.*rand(N_part_gen)-1.) 30 | y_part = R_charge*(2.*rand(N_part_gen)-1.) 31 | mask_keep = x_part**2+y_part**2x_on_tree*0.8) 53 | x_part = x_part[mask_keep] 54 | y_part = y_part[mask_keep] 55 | 56 | nel_part = 0*x_part+1 57 | 58 | 59 | 60 | 61 | 62 | chamber = poly.polyg_cham_geom_object({'Vx':na([x_aper, -x_aper, -x_aper, x_aper]), 63 | 'Vy':na([y_aper, y_aper, -y_aper, -y_aper]), 64 | 'x_sem_ellip_insc':0.99*x_aper, 65 | 'y_sem_ellip_insc':0.99*y_aper}) 66 | 67 | picFDSW = PIC_FDSW.FiniteDifferences_ShortleyWeller_SquareGrid(chamb = chamber, Dh = Dh) 68 | picFFTPEC = PIC_PEC_FFT.FFT_PEC_Boundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh, fftlib='pyfftw') 69 | picFFT = PIC_FFT.FFT_OpenBoundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh) 70 | 71 | picFDSW.scatter(x_part, y_part, nel_part) 72 | picFFTPEC.scatter(x_part, y_part, nel_part) 73 | picFFT.scatter(x_part, y_part, nel_part) 74 | 75 | 76 | picFDSW.solve() 77 | picFFTPEC.solve() 78 | picFFT.solve() 79 | 80 | 81 | pl.close('all') 82 | pl.figure(1) 83 | #pl.plot(x_tree, y_tree, '-o') 84 | pl.plot(x_part, y_part, '.g', markersize=2) 85 | pl.axis('equal') 86 | pl.suptitle('Macroparticle positions') 87 | pl.savefig('Xmas_MPs.png', dpi=200) 88 | 89 | pl.figure(2) 90 | pl.pcolor(picFFTPEC.rho.T) 91 | pl.axis('equal') 92 | pl.colorbar() 93 | pl.suptitle('Charge density') 94 | pl.savefig('Xmas_rho.png', dpi=200) 95 | 96 | 97 | pl.figure(3) 98 | pl.pcolor((picFFTPEC.efx**2+picFFTPEC.efy**2).T) 99 | pl.axis('equal') 100 | pl.suptitle('Magnitude electric field\n') 101 | pl.colorbar() 102 | pl.savefig('Xmas_efield_FFT.png', dpi=200) 103 | 104 | 105 | pl.figure(4) 106 | pl.pcolor(picFFTPEC.phi.T) 107 | pl.colorbar() 108 | pl.axis('equal') 109 | 110 | 111 | 112 | 113 | pl.figure(102) 114 | pl.pcolor(picFDSW.rho.T) 115 | pl.axis('equal') 116 | pl.suptitle('Charge density') 117 | 118 | 119 | pl.figure(103) 120 | pl.pcolor((picFDSW.efx**2+picFDSW.efy**2).T) 121 | pl.axis('equal') 122 | pl.suptitle('Magnitude electric field\nFinite differences') 123 | pl.colorbar() 124 | pl.savefig('Xmas_efield_FD.png', dpi=200) 125 | 126 | pl.figure(104) 127 | pl.pcolor(picFDSW.phi.T) 128 | pl.colorbar() 129 | pl.axis('equal') 130 | 131 | pl.figure(203) 132 | pl.pcolor((picFFT.efx**2+picFFT.efy**2).T) 133 | pl.axis('equal') 134 | pl.suptitle('Magnitude electric field - free space') 135 | pl.colorbar() 136 | pl.savefig('Xmas_efield_open_boudary.png', dpi=200) 137 | 138 | 139 | pl.show() 140 | -------------------------------------------------------------------------------- /GPU/test/004_test_gaussian.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | BIN=os.path.expanduser('../') 3 | sys.path.append(BIN) 4 | from backwards_compatibility_1_03 import * 5 | import FiniteDifferences_ShortleyWeller_SquareGrid as PIC_FDSW 6 | import FiniteDifferences_Staircase_SquareGrid as PIC_FD 7 | import FFT_OpenBoundary_SquareGrid as PIC_FFT 8 | import geom_impact_ellip as ell 9 | from scipy import rand 10 | import numpy as np 11 | 12 | sigma = .5 13 | 14 | R_cham = 10*sigma 15 | Dh = sigma/20. 16 | 17 | from scipy.constants import e, epsilon_0 18 | 19 | qe = e 20 | eps0 = epsilon_0 21 | 22 | 23 | chamber = ell.ellip_cham_geom_object(x_aper = R_cham, y_aper = R_cham) 24 | 25 | #~ picFD = PIC_FD.FiniteDifferences_Staircase_SquareGrid(chamb = chamber, Dh = Dh) 26 | #~ picFDSW = PIC_FDSW.FiniteDifferences_ShortleyWeller_SquareGrid(chamb = chamber, Dh = Dh) 27 | picFFT = PIC_FFT.FFT_OpenBoundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh) 28 | 29 | YY,XX = np.meshgrid(picFFT.yg, picFFT.xg) 30 | sigmax = sigma 31 | sigmay = sigma 32 | x_beam_pos = 0. 33 | y_beam_pos = 0. 34 | rho_mat=1./(2.*np.pi*sigmax*sigmay)*np.exp(-(XX-x_beam_pos)**2/(2.*sigmax**2)-(YY-y_beam_pos)**2/(2.*sigmay**2)) 35 | 36 | 37 | #pic scatter 38 | #~ picFD.solve(rho = rho_mat) 39 | #~ picFDSW.solve(rho = rho_mat) 40 | picFFT.solve(rho = rho_mat) 41 | 42 | x_probes = np.linspace(0,R_cham,1000) 43 | y_probes = 0.*x_probes 44 | 45 | #pic gather 46 | #~ Ex_FD, Ey_FD = picFD.gather(x_probes, y_probes) 47 | #~ Ex_FDSW, Ey_FDSW = picFDSW.gather(x_probes, y_probes) 48 | Ex_FFT, Ey_FFT = picFFT.gather(x_probes, y_probes) 49 | 50 | E_r_th = [np.sum(rho_mat[:][XX[:]**2+YY[:]**2x_on_tree*0.8) 52 | x_part = x_part[mask_keep] 53 | y_part = y_part[mask_keep] 54 | 55 | nel_part = 0*x_part+1. 56 | 57 | 58 | 59 | 60 | 61 | chamber = poly.polyg_cham_geom_object({'Vx':na([x_aper, -x_aper, -x_aper, x_aper]), 62 | 'Vy':na([y_aper, y_aper, -y_aper, -y_aper]), 63 | 'x_sem_ellip_insc':0.99*x_aper, 64 | 'y_sem_ellip_insc':0.99*y_aper}) 65 | 66 | 67 | 68 | picFFT = PIC_FFT.FFT_OpenBoundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh) 69 | 70 | 71 | picFFT.scatter(x_part, y_part, nel_part) 72 | 73 | data = picFFT.fgreen 74 | 75 | N_rep = 1000 76 | 77 | 78 | t_start_npfft = time.mktime(time.localtime()) 79 | for _ in range(N_rep): 80 | transf = np.fft.fft2(data) 81 | itransf = np.real(np.fft.ifft2(transf*data)) 82 | 83 | t_stop_npfft = time.mktime(time.localtime()) 84 | t_npfft = t_stop_npfft-t_start_npfft 85 | print('t_npfft', t_npfft) 86 | 87 | 88 | 89 | import pyfftw 90 | 91 | fftobj = pyfftw.builders.fft2(data.copy()) 92 | temptransf = fftobj(data) 93 | ifftobj = pyfftw.builders.ifft2(temptransf) 94 | 95 | t_start_npfftw = time.mktime(time.localtime()) 96 | for _ in range(N_rep): 97 | transfw = fftobj(data) 98 | itransfw = ifftobj(transfw) 99 | t_stop_npfftw = time.mktime(time.localtime()) 100 | t_npfftw = t_stop_npfftw-t_start_npfftw 101 | print('t_npfftw', t_npfftw) 102 | 103 | 104 | -------------------------------------------------------------------------------- /GPU/test/006_time_solve.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | BIN=os.path.expanduser('../') 3 | sys.path.append(BIN) 4 | from backwards_compatibility_1_03 import * 5 | import pylab as pl 6 | import numpy as np 7 | from scipy import rand 8 | import geom_impact_poly as poly 9 | import FiniteDifferences_ShortleyWeller_SquareGrid as PIC_FDSW 10 | import FFT_OpenBoundary_SquareGrid as PIC_FFT 11 | import FFT_PEC_Boundary_SquareGrid as PIC_PEC_FFT 12 | 13 | na = np.array 14 | Dh =1e-1 15 | N_part_gen = 100000 16 | 17 | tree = [[0,0], 18 | [1.,0], 19 | [1., 1,], 20 | [5.,1.], 21 | [2.,4.], 22 | [4,4], 23 | [2,7], 24 | [3,7], 25 | [1,9], 26 | [2,9], 27 | [0,11]] 28 | 29 | tree=np.array(tree) 30 | x_tree = tree[:,0] 31 | y_tree = tree[:,1] 32 | 33 | y_tree -= 6. 34 | 35 | x_aper = 6. 36 | y_aper = 7. 37 | 38 | x_tree = np.array([0.]+ list(x_tree)+[0.]) 39 | y_tree = np.array([-y_aper]+ list(y_tree)+[y_aper]) 40 | 41 | 42 | 43 | 44 | 45 | x_part = x_aper*(2.*rand(N_part_gen)-1.) 46 | y_part = y_aper*(2.*rand(N_part_gen)-1.) 47 | 48 | x_on_tree = np.interp(y_part, y_tree, x_tree) 49 | 50 | mask_keep = np.logical_and(np.abs(x_part)x_on_tree*0.8) 51 | x_part = x_part[mask_keep] 52 | y_part = y_part[mask_keep] 53 | 54 | nel_part = 0*x_part+1. 55 | 56 | 57 | 58 | 59 | 60 | chamber = poly.polyg_cham_geom_object({'Vx':na([x_aper, -x_aper, -x_aper, x_aper]), 61 | 'Vy':na([y_aper, y_aper, -y_aper, -y_aper]), 62 | 'x_sem_ellip_insc':0.99*x_aper, 63 | 'y_sem_ellip_insc':0.99*y_aper}) 64 | 65 | picFDSW = PIC_FDSW.FiniteDifferences_ShortleyWeller_SquareGrid(chamb = chamber, Dh = Dh) 66 | picFFTPEC = PIC_PEC_FFT.FFT_PEC_Boundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh, fftlib='pyfftw') 67 | #picFFTPEC = PIC_PEC_FFT.FFT_PEC_Boundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh, fftlib='numpy') 68 | picFFT = PIC_FFT.FFT_OpenBoundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh, fftlib='pyfftw') 69 | 70 | picFDSW.scatter(x_part, y_part, nel_part) 71 | picFFTPEC.scatter(x_part, y_part, nel_part) 72 | picFFT.scatter(x_part, y_part, nel_part) 73 | 74 | N_rep = 1000 75 | 76 | import time 77 | t_start_sw = time.mktime(time.localtime()) 78 | for _ in range(N_rep): 79 | picFDSW.solve() 80 | t_stop_sw = time.mktime(time.localtime()) 81 | t_sw = t_stop_sw-t_start_sw 82 | print('t_sw', t_sw) 83 | 84 | 85 | t_start_fftpec = time.mktime(time.localtime()) 86 | print('start fft PEC') 87 | for _ in range(N_rep): 88 | picFFTPEC.solve() 89 | t_stop_fftpec = time.mktime(time.localtime()) 90 | t_fftpec = t_stop_fftpec-t_start_fftpec 91 | print('t_fftpec', t_fftpec) 92 | 93 | 94 | t_start_fftopen = time.mktime(time.localtime()) 95 | for _ in range(N_rep): 96 | picFFT.solve() 97 | t_stop_fftopen = time.mktime(time.localtime()) 98 | t_fftopen = t_stop_fftopen-t_start_fftopen 99 | print('t_fftopen', t_fftopen) 100 | 101 | 102 | -------------------------------------------------------------------------------- /GPU/test/007_test_separately.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | BIN=os.path.expanduser('../') 3 | sys.path.append(BIN) 4 | from backwards_compatibility_1_03 import * 5 | import FiniteDifferences_ShortleyWeller_SquareGrid as PIC_FDSW 6 | import FiniteDifferences_Staircase_SquareGrid as PIC_FD 7 | import FFT_OpenBoundary_SquareGrid as PIC_FFT 8 | import geom_impact_ellip as ell 9 | from scipy import rand 10 | import numpy as np 11 | 12 | R_cham = 1e-1 13 | R_charge = 4e-2 14 | N_part_gen = 100000 15 | Dh = 1e-3 16 | 17 | from scipy.constants import e, epsilon_0 18 | 19 | qe = e 20 | eps0 = epsilon_0 21 | 22 | 23 | chamber = ell.ellip_cham_geom_object(x_aper = R_cham, y_aper = R_cham) 24 | 25 | picFFT = PIC_FFT.FFT_OpenBoundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh, fftlib = 'pyfftw') 26 | 27 | # generate particles 28 | x_part = R_charge*(2.*rand(N_part_gen)-1.) 29 | y_part = R_charge*(2.*rand(N_part_gen)-1.) 30 | mask_keep = x_part**2+y_part**2sigmay: 119 | 120 | S=np.sqrt(2*(sigmax*sigmax-sigmay*sigmay)); 121 | factBE=1/(2*eps0*np.sqrt(np.pi)*S); 122 | etaBE=sigmay/sigmax*x+1j*sigmax/sigmay*y; 123 | zetaBE=x+1j*y; 124 | 125 | val=factBE*(wfun(zetaBE/S)-np.exp( -x*x/(2*sigmax*sigmax)-y*y/(2*sigmay*sigmay))*wfun(etaBE/S) ); 126 | 127 | Ex=abs(val.imag)*np.sign(xin); 128 | Ey=abs(val.real)*np.sign(yin); 129 | 130 | else: 131 | 132 | S=np.sqrt(2*(sigmay*sigmay-sigmax*sigmax)); 133 | factBE=1/(2*eps0*np.sqrt(pi)*S); 134 | etaBE=sigmax/sigmay*y+1j*sigmay/sigmax*x; 135 | yetaBE=y+1j*x; 136 | 137 | val=factBE*(wfun(yetaBE/S)-np.exp( -y*y/(2*sigmay*sigmay)-x*x/(2*sigmax*sigmax))*wfun(etaBE/S) ); 138 | 139 | Ey=abs(val.imag)*np.sign(yin); 140 | Ex=abs(val.real)*np.sign(xin); 141 | 142 | return Ex, Ey 143 | 144 | def ImageTerms(x,y,a,b,x0,y0, nimag): 145 | 146 | 147 | eps0=epsilon_0; 148 | 149 | if nimag>0 and abs((a-b)/a)>1e-3: 150 | g=np.sqrt(a*a-b*b) 151 | z=x+1j*y 152 | q=np.arccosh(z/g) 153 | mu=q.real 154 | phi=q.imag 155 | 156 | z0=x0+1j*y0 157 | q0=np.arccosh(z0/g) 158 | mu0=q0.real 159 | phi0=q0.imag 160 | 161 | mu1=0.5*np.log((a+b)/(a-b)) 162 | 163 | Ecpx=0+0j 164 | 165 | 166 | q=np.conj(q) 167 | for nn in range(1,nimag+1): 168 | Ecpx=Ecpx+np.exp(-nn*mu1) * ( (np.cosh(nn*mu0)*np.cos(nn*phi0)) / (np.cosh(nn*mu1)) + 1j * (np.sinh(nn*mu0)*np.sin(nn*phi0)) / (np.sinh(nn*mu1)) )* (np.sinh(nn*q))/(np.sinh(q)) 169 | 170 | 171 | Ecpx=Ecpx/(4*np.pi*eps0)*4/g 172 | Ex=Ecpx.real 173 | Ey=Ecpx.imag 174 | else: 175 | if (x0==0) and (y0==0): 176 | Ex=0. 177 | Ey=0. 178 | else: 179 | print('This case has not been implemented yet') 180 | 181 | return Ex, Ey 182 | 183 | 184 | -------------------------------------------------------------------------------- /GPU/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyCOMPLETE/PyPIC/2b011d901149fad22a6a0d0d4304034f985aa00a/GPU/test/__init__.py -------------------------------------------------------------------------------- /GPU/test/myloadmat_to_obj.py: -------------------------------------------------------------------------------- 1 | import scipy.io as sio 2 | import numpy as np 3 | 4 | def myloadmat(filename): 5 | dict_var=sio.loadmat(filename) 6 | for kk in list(dict_var.keys()): 7 | try: 8 | dict_var[kk]=np.squeeze(dict_var[kk]) 9 | except: 10 | pass 11 | return dict_var 12 | 13 | class obj_from_dict: 14 | def __init__(self, dictto): 15 | for kk in list(dictto.keys()): 16 | exec('self.'+kk +'= dictto[kk]') 17 | 18 | 19 | def myloadmat_to_obj(filename): 20 | return obj_from_dict(myloadmat(filename)) 21 | -------------------------------------------------------------------------------- /GPU/test/mystyle.py: -------------------------------------------------------------------------------- 1 | from matplotlib import rc, rcdefaults 2 | import pylab as pl 3 | 4 | 5 | 6 | def mystyle(fontsz=10): 7 | 8 | font = {#'family' : 'normal', 9 | #'weight' : 'bold', 10 | 'size' : fontsz} 11 | print(fontsz) 12 | rcdefaults() 13 | rc('font', **font) 14 | 15 | def mystyle_arial(fontsz=10, dist_tick_lab=7): 16 | 17 | rcdefaults() 18 | rc('font',**{'family':'sans-serif','sans-serif':['arial'], 'size':fontsz}) 19 | rc(('xtick.major','xtick.minor','ytick.major','ytick.minor'), pad=dist_tick_lab) 20 | 21 | 22 | 23 | def sciy(): 24 | pl.gca().ticklabel_format(style='sci', scilimits=(0,0),axis='y') 25 | 26 | def scix(): 27 | pl.gca().ticklabel_format(style='sci', scilimits=(0,0),axis='x') 28 | -------------------------------------------------------------------------------- /GPU/vectsum.f: -------------------------------------------------------------------------------- 1 | *----------------------------------------------------------------------* 2 | * COMPILE USING 3 | * f2py -m vectsum -c vectsum.f 4 | 5 | subroutine vectsum(N_mp, x, res) 6 | Cf2py intent(in) N_mp 7 | Cf2py intent(in) x 8 | Cf2py intent(out) res 9 | implicit none 10 | integer N_mp 11 | integer p 12 | real*8 x(N_mp) 13 | real*8 res 14 | 15 | res = 0 16 | 17 | do p=1,N_mp 18 | res = res+x(p) 19 | end do 20 | 21 | end subroutine 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: f2py 2 | 3 | f2py: 4 | f2py -m rhocompute -c compute_rho.f 5 | f2py -m int_field_for -c interp_field_for.f 6 | f2py -m int_field_for_border -c interp_field_for_with_border.f 7 | f2py -m errffor -c errfff.f 8 | 9 | cythonize: 10 | python setup.py build_ext -i 11 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PyCOMPLETE/PyPIC/2b011d901149fad22a6a0d0d4304034f985aa00a/__init__.py -------------------------------------------------------------------------------- /change_version_number.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | files = os.listdir('.') 4 | 5 | for filename in files: 6 | if filename[-3:] == '.py': 7 | print(filename) 8 | os.system('cp %s %s'%(filename, filename+'old')) 9 | with open(filename) as fid: 10 | content=fid.read() 11 | if 'giovanni.iadarola@cern.ch' in content: 12 | content=content.replace('PyPIC Version 2.4.5', 'PyPIC Version 2.4.5') 13 | with open(filename,'w') as fid: 14 | fid.write(content) 15 | 16 | os.system('rm *.pyold') 17 | -------------------------------------------------------------------------------- /compute_rho.f: -------------------------------------------------------------------------------- 1 | *----------------------------------------------------------------------* 2 | * COMPILE USING 3 | * f2py -m rhocompute -c compute_rho.f 4 | 5 | subroutine compute_sc_rho(N_mp,x_mp, y_mp,nel_mp, bias_x, 6 | + bias_y, dx, dy, Nxg, Nyg,rho) 7 | Cf2py intent(in) N_mp 8 | Cf2py intent(in) x_mp 9 | Cf2py intent(in) y_mp 10 | Cf2py intent(in) nel_mp 11 | Cf2py intent(in) bias_x 12 | Cf2py intent(in) bias_y 13 | Cf2py intent(in) dx 14 | Cf2py intent(in) dy 15 | Cf2py intent(in) Nxg 16 | Cf2py intent(in) Nyg 17 | Cf2py intent(out) rho 18 | implicit none 19 | integer N_mp 20 | real*8 x_mp(N_mp), y_mp(N_mp), nel_mp(N_mp) 21 | real*8 bias_x, bias_y, dx, dy 22 | integer Nxg, Nyg 23 | real*8 rho(Nxg, Nyg) 24 | integer p 25 | real*8 nel_mp_curr, fi, fj, hx, hy 26 | integer i, j 27 | 28 | !rho=0d0; 29 | do j=1,Nyg 30 | do i=1,Nxg 31 | rho(i,j)=0.0 32 | end do 33 | end do 34 | !write(*,*) 'ciao fortran' 35 | 36 | do p=1,N_mp 37 | !loop over particles 38 | 39 | fi = 1+(x_mp(p)-bias_x)/dx; !real i index of particle's cell 40 | i = int(fi); !integral part 41 | hx = fi-dble(i); !the remainder 42 | 43 | 44 | fj = 1+(y_mp(p)-bias_y)/dy; !real j index of particle's cell (C-like indexing) 45 | j = int(fj); !integral part 46 | hy = fj-dble(j); !the remainder 47 | 48 | nel_mp_curr=nel_mp(p); 49 | 50 | if (i>0 .and. j>0 .and. i=1); 72 | 73 | def impact_point_and_normal(self, x_in, y_in, z_in, x_out, y_out, z_out, resc_fac=0.99, flag_robust=True): 74 | 75 | self.N_mp_impact=self.N_mp_impact+len(x_in) 76 | 77 | a=self.x_aper 78 | b=self.y_aper 79 | 80 | x_insq=x_in*x_in; 81 | y_insq=y_in*y_in; 82 | x_outsq=x_out*x_out; 83 | y_outsq=y_out*y_out; 84 | y_in__y_out=y_in*y_out; 85 | x_in__x_out=x_in*x_out; 86 | 87 | 88 | t0=(a**2*y_insq - a**2*y_in__y_out + \ 89 | sqrt(a**4*b**2*y_insq - 2*a**4*b**2*y_in__y_out \ 90 | + a**4*b**2*y_outsq + \ 91 | a**2*b**4*x_insq - 2*a**2*b**4*x_in__x_out + \ 92 | a**2*b**4*x_outsq - a**2*b**2*x_insq* \ 93 | y_outsq + 2*a**2*b**2*x_in__x_out*y_in__y_out - \ 94 | a**2*b**2*x_outsq*y_insq) + b**2*x_insq - \ 95 | b**2*x_in__x_out)/(a**2*y_insq - \ 96 | 2*a**2*y_in__y_out + a**2*y_outsq + b**2*x_insq - \ 97 | 2*b**2*x_in__x_out + b**2*x_outsq); 98 | 99 | 100 | 101 | # Handle pathological cases 102 | mask_nan = isnan(t0) 103 | if sum(mask_nan)>0: 104 | t0[mask_nan]=0. 105 | if self.flag_verbose_file: 106 | x_nan=x_in[mask_nan] 107 | y_nan=y_in[mask_nan] 108 | fbckt=open('bcktr_errors.txt','a') 109 | for ii_bk in range(len(y_nan)): 110 | fbckt.write('%e\t%e\tnan\n'%(x_nan[ii_bk],y_nan[ii_bk])) 111 | fbckt.close() 112 | 113 | t0=resc_fac*t0; 114 | 115 | t0[t0<1.e-2]=0; 116 | 117 | flag_ident=(((x_in-x_out)*(x_in-x_out)+(y_in-y_out)*(y_in-y_out))/(x_out*x_out+y_out*y_out))<1e-8; 118 | t0[flag_ident]=0; 119 | 120 | 121 | 122 | if sum(abs(t0.imag))>0: 123 | print('imag detected') 124 | raise ValueError('Backtracking: complex t0!!!!') 125 | 126 | x_int=t0*x_out+(1-t0)*x_in; 127 | y_int=t0*y_out+(1-t0)*y_in; 128 | z_int=t0*z_out+(1-t0)*z_in; 129 | 130 | 131 | if flag_robust: 132 | flag_impact=(((x_int/a)**2 + (y_int/b)**2)>1); 133 | 134 | 135 | if flag_impact.any(): 136 | self.N_mp_corrected = self.N_mp_corrected + sum(flag_impact) 137 | ntrials=10 138 | while (sum(flag_impact)>0 and ntrials>0): 139 | t0[flag_impact]=0.9*t0[flag_impact]; 140 | x_int=t0*x_out+(1-t0)*x_in; 141 | y_int=t0*y_out+(1-t0)*y_in; 142 | z_int=t0*z_out+(1-t0)*z_in; 143 | 144 | flag_impact=(((x_int/a)**2 + (y_int/b)**2)>1); 145 | ntrials=ntrials-1 146 | 147 | flag_impact=(((x_int/a)**2 + (y_int/b)**2)>=1); 148 | if sum(flag_impact)>0: 149 | 150 | x_int_pat = x_int[flag_impact] 151 | y_int_pat = y_int[flag_impact] 152 | 153 | if self.flag_verbose_file: 154 | fbckt=open('bcktr_errors.txt','a') 155 | for ii_bk in range(len(x_int_pat)): 156 | fbckt.write('%e\t%e\n'%(x_int_pat[ii_bk],y_int_pat[ii_bk])) 157 | 158 | fbckt.close() 159 | 160 | 161 | x_pr=x_int_pat/a 162 | y_pr=y_int_pat/b 163 | 164 | r_pr=sqrt(x_pr**2+y_pr**2) 165 | 166 | x_pr=0.99*x_pr/r_pr 167 | y_pr=0.99*y_pr/r_pr 168 | 169 | x_int[flag_impact] = x_pr*a 170 | y_int[flag_impact] = y_pr*b 171 | 172 | 173 | 174 | 175 | flag_impact=(((x_int/a)**2 + (y_int/b)**2)>=1); 176 | if sum(flag_impact)>0: 177 | print('err inside') 178 | raise ValueError('Outside after backtracking!!!!') 179 | 180 | 181 | 182 | 183 | 184 | par_cross=arctan2(a*y_int,b*x_int); 185 | 186 | Dx=-a*sin(par_cross); 187 | Dy=b*cos(par_cross); 188 | 189 | Nx=-Dy; 190 | Ny=Dx; 191 | 192 | neg_flag=((Nx*x_int+Ny*y_int)>0); 193 | 194 | Nx[neg_flag]=-Nx[neg_flag]; 195 | Ny[neg_flag]=-Ny[neg_flag]; 196 | 197 | 198 | nor=sqrt(Nx*Nx+Ny*Ny); 199 | 200 | Nx=Nx/nor; 201 | Ny=Ny/nor; 202 | 203 | i_found=None 204 | 205 | return x_int,y_int,z_int,Nx,Ny, i_found 206 | 207 | def points_on_boundary(self, N_points): 208 | tt = np.linspace(0., 2*np.pi, N_points) 209 | return self.x_aper*cos(tt), self.y_aper*sin(tt) 210 | -------------------------------------------------------------------------------- /interp_field_for.f: -------------------------------------------------------------------------------- 1 | *----------------------------------------------------------------------* 2 | * COMPILE USING 3 | * f2py -m int_field_for -c interp_field_for.f 4 | 5 | subroutine int_field(N_mp,xn,yn, bias_x,bias_y, dx,dy,efx, efy, 6 | + Nxg, Nyg, Ex_n, Ey_n) 7 | Cf2py intent(in) N_mp 8 | Cf2py intent(in) xn 9 | Cf2py intent(in) yn 10 | Cf2py intent(in) bias_x 11 | Cf2py intent(in) bias_y 12 | Cf2py intent(in) dx 13 | Cf2py intent(in) dy 14 | Cf2py intent(in) efx 15 | Cf2py intent(in) efy 16 | Cf2py intent(in) Nxg 17 | Cf2py intent(in) Nyg 18 | Cf2py intent(out) Ex_n 19 | Cf2py intent(out) Ey_n 20 | 21 | 22 | implicit none 23 | integer N_mp 24 | real*8 xn(N_mp), yn(N_mp) 25 | real*8 bias_x, bias_y, dx, dy 26 | integer Nxg,Nyg 27 | real*8 efx(Nxg, Nyg), efy(Nxg, Nyg) 28 | integer p 29 | real*8 fi, fj, hx, hy 30 | integer i, j 31 | real*8 Ex_n(N_mp), Ey_n(N_mp) 32 | 33 | 34 | 35 | do p=1,N_mp 36 | fi = 1+(xn(p)-bias_x)/dx; !i index of particle's cell 37 | i = int(fi); 38 | hx = fi-dble(i); !fractional x position in cell 39 | 40 | 41 | fj = 1+(yn(p)-bias_y)/dy; !j index of particle' cell(C-like!!!!) 42 | j = int(fj); 43 | hy = fj-dble(j); !fractional y position in cell 44 | 45 | 46 | !gather electric field 47 | if (i>0 .and. j>0 .and. i0 .and. j>0 .and. i0.) then 92 | fact_correct = 1./(wei_ij+wei_i1j+wei_ij1+wei_i1j1) 93 | Ex_n(p) = Ex_n(p)*fact_correct 94 | Ey_n(p) = Ey_n(p)*fact_correct 95 | else 96 | Ex_n(p) = 0. 97 | Ey_n(p) = 0. 98 | end if 99 | end if 100 | 101 | end if 102 | end do 103 | 104 | 105 | 106 | end subroutine 107 | 108 | -------------------------------------------------------------------------------- /myloadmat_to_obj.py: -------------------------------------------------------------------------------- 1 | import scipy.io as sio 2 | import numpy as np 3 | 4 | def myloadmat(filename): 5 | dict_var=sio.loadmat(filename) 6 | for kk in list(dict_var.keys()): 7 | try: 8 | dict_var[kk]=np.squeeze(dict_var[kk]) 9 | except: 10 | pass 11 | return dict_var 12 | 13 | class obj_from_dict: 14 | def __init__(self, dictto): 15 | for kk in list(dictto.keys()): 16 | exec('self.'+kk +'= dictto[kk]') 17 | 18 | 19 | def myloadmat_to_obj(filename): 20 | return obj_from_dict(myloadmat(filename)) 21 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from setuptools import setup, Extension 4 | 5 | from Cython.Distutils import build_ext 6 | from Cython.Build import cythonize 7 | 8 | 9 | cy_ext_options = {"compiler_directives": {"profile": True}, "annotate": True} 10 | cy_ext = [ 11 | Extension( 12 | "CyFPPS", 13 | sources=[ # the Cython source and additional C++ source files generate and compile C++ code 14 | 'FPPS/CyFPPS.pyx', 'FPPS/FPPSWrapper.cc', 15 | 'FPPS/ChangeCoord.cc', 'FPPS/ElectricFieldSolver.cc', 'FPPS/Mesh.cc', 16 | 'FPPS/ChangeCoord_Frac.cc', 'FPPS/FastPolarPoissonSolver.cc', 'FPPS/NonLinearMesh.cc', 17 | 'FPPS/ChangeCoord_Tanh.cc', 'FPPS/PolarBeamRepresentation.cc', 18 | 'FPPS/ChargeDistribution.cc', 'FPPS/FunctionsFPPS.cc'], 19 | language="c++", include_dirs=[np.get_include()], libraries=['fftw3', 'm']) 20 | ] 21 | 22 | 23 | setup( 24 | name='PyPIC', 25 | description='Collection of Python Particle-In-Cell solvers.', 26 | url='http://github.com/PyCOMPLETE/PyPIC', 27 | packages=['PyPIC'], 28 | cmdclass={'build_ext': build_ext}, 29 | ext_modules=cythonize(cy_ext, **cy_ext_options), 30 | install_requires=[ 31 | 'numpy', 32 | 'cython' 33 | ] 34 | ) 35 | -------------------------------------------------------------------------------- /simple_polygon.py: -------------------------------------------------------------------------------- 1 | 2 | from numpy import squeeze, array,diff, min, max, sum, sqrt,\ 3 | logical_and, logical_or, ones, zeros, take, arctan2, sin, cos 4 | import scipy.io as sio 5 | 6 | class SimplePolygon(object): 7 | def __init__(self, filename_chm): 8 | 9 | if type(filename_chm)==str: 10 | dict_chm=sio.loadmat(filename_chm) 11 | else: 12 | dict_chm=filename_chm 13 | 14 | Vx=squeeze(dict_chm['Vx']) 15 | Vy=squeeze(dict_chm['Vy']) 16 | 17 | 18 | 19 | self.N_vert=len(Vx) 20 | 21 | N_edg=len(Vx) 22 | 23 | Vx=list(Vx) 24 | Vy=list(Vy) 25 | 26 | Vx.append(Vx[0]) 27 | Vy.append(Vy[0]) 28 | 29 | Vx=array(Vx) 30 | Vy=array(Vy) 31 | 32 | self.Vx=Vx 33 | self.Vy=Vy 34 | self.N_edg=N_edg 35 | self.x_min = min(self.Vx) 36 | self.x_max = max(self.Vx) 37 | self.y_min = min(self.Vy) 38 | self.y_max = max(self.Vy) 39 | 40 | self.N_mp_impact=0 41 | self.N_mp_corrected=0 42 | self.chamb_type='simple_polyg' 43 | 44 | 45 | def is_outside(self, x_mp, y_mp): 46 | 47 | x_mp_chk=x_mp 48 | y_mp_chk=y_mp 49 | N_pts=len(x_mp_chk) 50 | flag_inside_chk=array(N_pts*[True]) 51 | for ii in range(self.N_edg): 52 | flag_inside_chk[flag_inside_chk]=((y_mp_chk[flag_inside_chk]-self.Vy[ii])*(self.Vx[ii+1]-self.Vx[ii])\ 53 | -(x_mp_chk[flag_inside_chk]-self.Vx[ii])*(self.Vy[ii+1]-self.Vy[ii]))>0 54 | flag_outside=~flag_inside_chk 55 | 56 | return flag_outside 57 | 58 | 59 | -------------------------------------------------------------------------------- /tests/000_test_round_chamber.py: -------------------------------------------------------------------------------- 1 | import PyPIC.FiniteDifferences_ShortleyWeller_SquareGrid as PIC_FDSW 2 | import PyPIC.FiniteDifferences_Staircase_SquareGrid as PIC_FD 3 | import PyPIC.FFT_OpenBoundary as PIC_FFT 4 | try: 5 | from CyFPPS import PyFPPS as PIC_FPPS 6 | except ImportError: 7 | print("Not possible to import PyFPPS, replaced with FFT_Open") 8 | PIC_FPPS = None 9 | from PyPIC.MultiGrid import AddInternalGrid 10 | 11 | import PyPIC.geom_impact_ellip as ell 12 | from scipy import rand 13 | import numpy as np 14 | 15 | R_cham = 1e-1 16 | R_charge = 4e-2 17 | N_part_gen = 1000000 18 | Dh = 1e-3 19 | 20 | # Settings for dual grid 21 | x_min_internal = -R_charge*1.1 22 | x_max_internal = R_charge*1.1 23 | y_min_internal = -R_charge*1.2 24 | y_max_internal = R_charge*1.2 25 | Dh_main = 1e-3 26 | Dh_internal = .2e-3 27 | N_nodes_discard = 3 28 | 29 | 30 | from scipy.constants import e, epsilon_0 31 | 32 | qe = e 33 | eps0 = epsilon_0 34 | 35 | 36 | chamber = ell.ellip_cham_geom_object(x_aper = R_cham, y_aper = R_cham) 37 | 38 | picFD = PIC_FD.FiniteDifferences_Staircase_SquareGrid(chamb = chamber, Dh = Dh) 39 | picFDSW = PIC_FDSW.FiniteDifferences_ShortleyWeller_SquareGrid(chamb = chamber, Dh = Dh) 40 | picFFT = PIC_FFT.FFT_OpenBoundary(x_aper = chamber.x_aper, y_aper = chamber.y_aper, dx = Dh/2., dy = Dh, fftlib='pyfftw') 41 | picFFTSq = PIC_FFT.FFT_OpenBoundary(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh, fftlib='pyfftw') 42 | if PIC_FPPS: picFPPS = PIC_FPPS(200,200,a=R_cham,solverType='Uniform') 43 | # build dual grid 44 | pic_main = PIC_FDSW.FiniteDifferences_ShortleyWeller_SquareGrid(chamb = chamber, Dh = Dh_main) 45 | pic_dualgrid = AddInternalGrid(pic_main, x_min_internal, x_max_internal, y_min_internal, 46 | y_max_internal, Dh_internal, N_nodes_discard) 47 | 48 | # generate particles 49 | x_part = R_charge*(2.*rand(N_part_gen)-1.) 50 | y_part = R_charge*(2.*rand(N_part_gen)-1.) 51 | mask_keep = x_part**2+y_part**2x_on_tree*0.8) 49 | x_part = x_part[mask_keep] 50 | y_part = y_part[mask_keep] 51 | 52 | nel_part = 0*x_part+1. 53 | 54 | 55 | chamber = poly.polyg_cham_geom_object({'Vx':na([x_aper, -x_aper, -x_aper, x_aper]), 56 | 'Vy':na([y_aper, y_aper, -y_aper, -y_aper]), 57 | 'x_sem_ellip_insc':0.99*x_aper, 58 | 'y_sem_ellip_insc':0.99*y_aper}) 59 | 60 | picFDSW = PIC_FDSW.FiniteDifferences_ShortleyWeller_SquareGrid(chamb = chamber, Dh = Dh) 61 | picFFTPEC = PIC_PEC_FFT.FFT_PEC_Boundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh) 62 | picFFT = PIC_FFT.FFT_OpenBoundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh) 63 | R_cham = np.sqrt((chamber.x_aper/2)**2 + (chamber.y_aper/2)**2 ) 64 | if PIC_FPPS: picFPPS = PIC_FPPS(nTheta=100,nR=200,a=R_cham,solverType='OpenBoundary') 65 | 66 | picFDSW.scatter(x_part, y_part, nel_part) 67 | picFFTPEC.scatter(x_part, y_part, nel_part) 68 | picFFT.scatter(x_part, y_part, nel_part) 69 | if PIC_FPPS: picFPPS.scatter(x_part,y_part,nel_part) 70 | 71 | 72 | picFDSW.solve() 73 | picFFTPEC.solve() 74 | picFFT.solve() 75 | if PIC_FPPS: picFPPS.solve() 76 | 77 | pl.close('all') 78 | pl.figure(1) 79 | #pl.plot(x_tree, y_tree, '-o') 80 | pl.plot(x_part, y_part, '.g', markersize=2) 81 | pl.axis('equal') 82 | pl.suptitle('Macroparticle positions') 83 | pl.savefig('Xmas_MPs.png', dpi=200) 84 | 85 | pl.figure(2) 86 | pl.pcolor(picFFTPEC.rho.T) 87 | pl.axis('equal') 88 | pl.suptitle('Charge density') 89 | pl.savefig('Xmas_rho.png', dpi=200) 90 | 91 | pl.figure(3) 92 | pl.pcolor((picFFTPEC.efx**2+picFFTPEC.efy**2).T) 93 | pl.axis('equal') 94 | pl.suptitle('Magnitude electric field\nFFT') 95 | pl.colorbar() 96 | pl.savefig('Xmas_efield_FFT.png', dpi=200) 97 | 98 | pl.figure(4) 99 | pl.pcolor(picFFTPEC.phi.T) 100 | pl.colorbar() 101 | pl.axis('equal') 102 | 103 | 104 | pl.figure(102) 105 | pl.pcolor(picFDSW.rho.T) 106 | pl.axis('equal') 107 | pl.suptitle('Charge density') 108 | 109 | 110 | pl.figure(103) 111 | pl.pcolor((picFDSW.efx**2+picFDSW.efy**2).T) 112 | pl.axis('equal') 113 | pl.suptitle('Magnitude electric field\nFinite differences') 114 | pl.colorbar() 115 | pl.savefig('Xmas_efield_FD.png', dpi=200) 116 | 117 | pl.figure(104) 118 | pl.pcolor(picFDSW.phi.T) 119 | pl.colorbar() 120 | pl.axis('equal') 121 | 122 | pl.figure(203) 123 | pl.pcolor((picFFT.efx**2+picFFT.efy**2).T) 124 | pl.axis('equal') 125 | pl.suptitle('Magnitude electric field - free space') 126 | pl.colorbar() 127 | pl.savefig('Xmas_efield_open_boudary.png', dpi=200) 128 | 129 | if PIC_FPPS: 130 | x = np.arange(-chamber.x_aper,chamber.x_aper,2*chamber.x_aper/300) 131 | y = np.arange(-chamber.y_aper,chamber.y_aper,2*chamber.y_aper/300) 132 | X,Y = np.meshgrid(x,y) 133 | E = np.zeros_like(X) 134 | for i in range(np.shape(X)[0]): 135 | Ex_FPPS,Ey_FPPS = picFPPS.gather(X[i,:],Y[i,:]) 136 | print((np.shape(Ex_FPPS))) 137 | E[i,:] = Ex_FPPS**2+Ey_FPPS**2 138 | pl.figure(303) 139 | pl.pcolor(X,Y,E) 140 | pl.axis('equal') 141 | pl.suptitle('Magnitude electric field - free space') 142 | pl.colorbar() 143 | pl.savefig('Xmas_efield_FPPS_openBoundary.png', dpi=200) 144 | 145 | 146 | pl.show() 147 | -------------------------------------------------------------------------------- /tests/004_test_gaussian.py: -------------------------------------------------------------------------------- 1 | import PyPIC.FiniteDifferences_ShortleyWeller_SquareGrid as PIC_FDSW 2 | import PyPIC.FiniteDifferences_Staircase_SquareGrid as PIC_FD 3 | import PyPIC.FFT_OpenBoundary_SquareGrid as PIC_FFT 4 | import PyPIC.geom_impact_ellip as ell 5 | 6 | from scipy import rand 7 | import numpy as np 8 | 9 | sigma = .5 10 | 11 | R_cham = 10*sigma 12 | Dh = sigma/20. 13 | 14 | from scipy.constants import e, epsilon_0 15 | 16 | qe = e 17 | eps0 = epsilon_0 18 | 19 | 20 | chamber = ell.ellip_cham_geom_object(x_aper = R_cham, y_aper = R_cham) 21 | 22 | #~ picFD = PIC_FD.FiniteDifferences_Staircase_SquareGrid(chamb = chamber, Dh = Dh) 23 | #~ picFDSW = PIC_FDSW.FiniteDifferences_ShortleyWeller_SquareGrid(chamb = chamber, Dh = Dh) 24 | picFFT = PIC_FFT.FFT_OpenBoundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh) 25 | 26 | YY,XX = np.meshgrid(picFFT.yg, picFFT.xg) 27 | sigmax = sigma 28 | sigmay = sigma 29 | x_beam_pos = 0. 30 | y_beam_pos = 0. 31 | rho_mat=1./(2.*np.pi*sigmax*sigmay)*np.exp(-(XX-x_beam_pos)**2/(2.*sigmax**2)-(YY-y_beam_pos)**2/(2.*sigmay**2)) 32 | 33 | 34 | #pic scatter 35 | #~ picFD.solve(rho = rho_mat) 36 | #~ picFDSW.solve(rho = rho_mat) 37 | picFFT.solve(rho = rho_mat) 38 | 39 | x_probes = np.linspace(0,R_cham,1000) 40 | y_probes = 0.*x_probes 41 | 42 | #pic gather 43 | #~ Ex_FD, Ey_FD = picFD.gather(x_probes, y_probes) 44 | #~ Ex_FDSW, Ey_FDSW = picFDSW.gather(x_probes, y_probes) 45 | Ex_FFT, Ey_FFT = picFFT.gather(x_probes, y_probes) 46 | 47 | E_r_th = [np.sum(rho_mat[:][XX[:]**2+YY[:]**2x_on_tree*0.8) 46 | x_part = x_part[mask_keep] 47 | y_part = y_part[mask_keep] 48 | 49 | nel_part = 0*x_part+1. 50 | 51 | 52 | chamber = poly.polyg_cham_geom_object({'Vx':na([x_aper, -x_aper, -x_aper, x_aper]), 53 | 'Vy':na([y_aper, y_aper, -y_aper, -y_aper]), 54 | 'x_sem_ellip_insc':0.99*x_aper, 55 | 'y_sem_ellip_insc':0.99*y_aper}) 56 | 57 | picFFT = PIC_FFT.FFT_OpenBoundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh) 58 | 59 | 60 | picFFT.scatter(x_part, y_part, nel_part) 61 | 62 | data = picFFT.fgreen 63 | 64 | N_rep = 1000 65 | 66 | 67 | t_start_npfft = time.mktime(time.localtime()) 68 | for _ in range(N_rep): 69 | transf = np.fft.fft2(data) 70 | itransf = np.real(np.fft.ifft2(transf*data)) 71 | 72 | t_stop_npfft = time.mktime(time.localtime()) 73 | t_npfft = t_stop_npfft-t_start_npfft 74 | print('t_npfft', t_npfft) 75 | 76 | 77 | 78 | import pyfftw 79 | 80 | fftobj = pyfftw.builders.fft2(data.copy()) 81 | temptransf = fftobj(data) 82 | ifftobj = pyfftw.builders.ifft2(temptransf) 83 | 84 | t_start_npfftw = time.mktime(time.localtime()) 85 | for _ in range(N_rep): 86 | transfw = fftobj(data) 87 | itransfw = ifftobj(transfw) 88 | t_stop_npfftw = time.mktime(time.localtime()) 89 | t_npfftw = t_stop_npfftw-t_start_npfftw 90 | print('t_npfftw', t_npfftw) 91 | 92 | 93 | -------------------------------------------------------------------------------- /tests/006_time_solve.py: -------------------------------------------------------------------------------- 1 | import pylab as pl 2 | import numpy as np 3 | from scipy import rand 4 | 5 | import PyPIC.geom_impact_poly as poly 6 | import PyPIC.FiniteDifferences_ShortleyWeller_SquareGrid as PIC_FDSW 7 | import PyPIC.FFT_OpenBoundary_SquareGrid as PIC_FFT 8 | import PyPIC.FFT_PEC_Boundary_SquareGrid as PIC_PEC_FFT 9 | 10 | na = np.array 11 | Dh =1e-1 12 | N_part_gen = 100000 13 | 14 | tree = [[0,0], 15 | [1.,0], 16 | [1., 1,], 17 | [5.,1.], 18 | [2.,4.], 19 | [4,4], 20 | [2,7], 21 | [3,7], 22 | [1,9], 23 | [2,9], 24 | [0,11]] 25 | 26 | tree=np.array(tree) 27 | x_tree = tree[:,0] 28 | y_tree = tree[:,1] 29 | 30 | y_tree -= 6. 31 | 32 | x_aper = 6. 33 | y_aper = 7. 34 | 35 | x_tree = np.array([0.]+ list(x_tree)+[0.]) 36 | y_tree = np.array([-y_aper]+ list(y_tree)+[y_aper]) 37 | 38 | 39 | x_part = x_aper*(2.*rand(N_part_gen)-1.) 40 | y_part = y_aper*(2.*rand(N_part_gen)-1.) 41 | 42 | x_on_tree = np.interp(y_part, y_tree, x_tree) 43 | 44 | mask_keep = np.logical_and(np.abs(x_part)x_on_tree*0.8) 45 | x_part = x_part[mask_keep] 46 | y_part = y_part[mask_keep] 47 | 48 | nel_part = 0*x_part+1. 49 | 50 | 51 | chamber = poly.polyg_cham_geom_object({'Vx':na([x_aper, -x_aper, -x_aper, x_aper]), 52 | 'Vy':na([y_aper, y_aper, -y_aper, -y_aper]), 53 | 'x_sem_ellip_insc':0.99*x_aper, 54 | 'y_sem_ellip_insc':0.99*y_aper}) 55 | 56 | picFDSW = PIC_FDSW.FiniteDifferences_ShortleyWeller_SquareGrid(chamb = chamber, Dh = Dh) 57 | picFFTPEC = PIC_PEC_FFT.FFT_PEC_Boundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh, fftlib='pyfftw') 58 | picFFT = PIC_FFT.FFT_OpenBoundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh, fftlib='pyfftw') 59 | 60 | picFDSW.scatter(x_part, y_part, nel_part) 61 | picFFTPEC.scatter(x_part, y_part, nel_part) 62 | picFFT.scatter(x_part, y_part, nel_part) 63 | 64 | N_rep = 1000 65 | 66 | import time 67 | t_start_sw = time.mktime(time.localtime()) 68 | for _ in range(N_rep): 69 | picFDSW.solve() 70 | t_stop_sw = time.mktime(time.localtime()) 71 | t_sw = t_stop_sw-t_start_sw 72 | print('t_sw', t_sw) 73 | 74 | 75 | t_start_fftpec = time.mktime(time.localtime()) 76 | for _ in range(N_rep): 77 | picFFTPEC.solve() 78 | t_stop_fftpec = time.mktime(time.localtime()) 79 | t_fftpec = t_stop_fftpec-t_start_fftpec 80 | print('t_fftpec', t_fftpec) 81 | 82 | 83 | t_start_fftopen = time.mktime(time.localtime()) 84 | for _ in range(N_rep): 85 | picFFT.solve() 86 | t_stop_fftopen = time.mktime(time.localtime()) 87 | t_fftopen = t_stop_fftopen-t_start_fftopen 88 | print('t_fftopen', t_fftopen) 89 | 90 | 91 | -------------------------------------------------------------------------------- /tests/007_test_separately.py: -------------------------------------------------------------------------------- 1 | import PyPIC.FiniteDifferences_ShortleyWeller_SquareGrid as PIC_FDSW 2 | import PyPIC.FiniteDifferences_Staircase_SquareGrid as PIC_FD 3 | import PyPIC.FFT_OpenBoundary_SquareGrid as PIC_FFT 4 | import PyPIC.geom_impact_ellip as ell 5 | 6 | from scipy import rand 7 | import numpy as np 8 | 9 | R_cham = 1e-1 10 | R_charge = 4e-2 11 | N_part_gen = 100000 12 | Dh = 1e-3 13 | 14 | from scipy.constants import e, epsilon_0 15 | 16 | qe = e 17 | eps0 = epsilon_0 18 | 19 | 20 | chamber = ell.ellip_cham_geom_object(x_aper = R_cham, y_aper = R_cham) 21 | 22 | picFFT = PIC_FFT.FFT_OpenBoundary_SquareGrid(x_aper = chamber.x_aper, y_aper = chamber.y_aper, Dh = Dh, fftlib = 'pyfftw') 23 | 24 | # generate particles 25 | x_part = R_charge*(2.*rand(N_part_gen)-1.) 26 | y_part = R_charge*(2.*rand(N_part_gen)-1.) 27 | mask_keep = x_part**2+y_part**2','').split('.')[-1].replace("'", '')) 116 | 117 | pl.show() 118 | -------------------------------------------------------------------------------- /tests/LHC.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.constants import c, e, m_p 3 | 4 | from PyHEADTAIL.machines.synchrotron import Synchrotron 5 | 6 | 7 | class EmptyObject(object): 8 | pass 9 | 10 | 11 | class LHC(Synchrotron): 12 | 13 | def __init__(self, machine_configuration=None, optics_mode='smooth', **kwargs): 14 | 15 | 16 | pp = EmptyObject() 17 | pp.machine_configuration = machine_configuration 18 | pp.optics_mode = optics_mode 19 | 20 | pp.longitudinal_mode = 'non-linear' 21 | pp.alpha = 3.225e-04 22 | pp.h_RF = 35640 23 | pp.mass = m_p 24 | pp.charge = e 25 | pp.RF_at = 'middle' 26 | 27 | if pp.machine_configuration == 'Injection': 28 | pp.p0 = 450e9 * e / c 29 | pp.p_increment = 0. 30 | pp.accQ_x = 64.28 31 | pp.accQ_y = 59.31 32 | pp.V_RF = 6e6 33 | pp.dphi_RF = 0. 34 | elif machine_configuration == '6.5_TeV_collision_tunes': 35 | pp.p0 = 6500e9 * e / c 36 | pp.p_increment = 0. 37 | pp.accQ_x = 64.31 38 | pp.accQ_y = 59.32 39 | pp.V_RF = 12e6 40 | pp.dphi_RF = 0. 41 | else: 42 | raise ValueError('machine_configuration not recognized!') 43 | 44 | if pp.optics_mode == 'smooth': 45 | if 's' in list(kwargs.keys()): 46 | raise ValueError('s vector cannot be provided if optics_mode = "smooth"') 47 | 48 | pp.n_segments = kwargs['n_segments'] 49 | pp.circumference = 26658.8832 50 | 51 | pp.name = None 52 | 53 | pp.beta_x = 92.7 54 | pp.D_x = 0 55 | pp.beta_y = 93.2 56 | pp.D_y = 0 57 | 58 | pp.alpha_x = None 59 | pp.alpha_y = None 60 | 61 | pp.s = None 62 | 63 | elif pp.optics_mode == 'non-smooth': 64 | if 'n_segments' in list(kwargs.keys()): 65 | raise ValueError('n_segments cannot be provided if optics_mode = "non-smooth"') 66 | pp.n_segments = None 67 | pp.circumference = None 68 | 69 | pp.name = kwargs['name'] 70 | 71 | pp.beta_x = kwargs['beta_x'] 72 | pp.beta_y = kwargs['beta_y'] 73 | 74 | try: 75 | pp.D_x = kwargs['D_x'] 76 | except KeyError: 77 | pp.D_x = 0 * np.array(kwargs['s']) 78 | try: 79 | pp.D_y = kwargs['D_y'] 80 | except KeyError: 81 | pp.D_y = 0 * np.array(kwargs['s']) 82 | 83 | pp.alpha_x = kwargs['alpha_x'] 84 | pp.alpha_y = kwargs['alpha_y'] 85 | 86 | pp.s = kwargs['s'] 87 | 88 | else: 89 | raise ValueError('optics_mode not recognized!') 90 | 91 | # detunings 92 | pp.Qp_x = 0 93 | pp.Qp_y = 0 94 | 95 | pp.app_x = 0 96 | pp.app_y = 0 97 | pp.app_xy = 0 98 | 99 | pp.i_octupole_focusing = None 100 | pp.i_octupole_defocusing = None 101 | pp.octupole_knob = None 102 | 103 | for attr in list(kwargs.keys()): 104 | if kwargs[attr] is not None: 105 | if type(kwargs[attr]) is list or type(kwargs[attr]) is np.ndarray: 106 | str2print = '[%s ...]'%repr(kwargs[attr][0]) 107 | else: 108 | str2print = repr(kwargs[attr]) 109 | self.prints('Synchrotron init. From kwargs: %s = %s' 110 | % (attr, str2print)) 111 | if not hasattr(pp, attr): 112 | raise NameError("I don't understand %s"%attr) 113 | 114 | setattr(pp, attr, kwargs[attr]) 115 | 116 | 117 | 118 | if pp.i_octupole_focusing is not None or pp.i_octupole_defocusing is not None: 119 | if pp.octupole_knob is not None: 120 | raise ValueError('octupole_knobs and octupole currents cannot be used at the same time!') 121 | pp.app_x, pp.app_y, pp.app_xy = self._anharmonicities_from_octupole_current_settings( 122 | pp.i_octupole_focusing, pp.i_octupole_defocusing) 123 | self.i_octupole_focusing = pp.i_octupole_focusing 124 | self.i_octupole_defocusing = pp.i_octupole_defocusing 125 | 126 | if pp.octupole_knob is not None: 127 | if pp.i_octupole_focusing is not None or pp.i_octupole_defocusing is not None: 128 | raise ValueError('octupole_knobs and octupole currents cannot be used at the same time!') 129 | pp.i_octupole_focusing, pp.i_octupole_defocusing = self._octupole_currents_from_octupole_knobs(pp.octupole_knob, pp.p0) 130 | pp.app_x, pp.app_y, pp.app_xy = self._anharmonicities_from_octupole_current_settings( 131 | pp.i_octupole_focusing, pp.i_octupole_defocusing) 132 | self.i_octupole_focusing = pp.i_octupole_focusing 133 | self.i_octupole_defocusing = pp.i_octupole_defocusing 134 | 135 | 136 | super(LHC, self).__init__(optics_mode=pp.optics_mode, circumference=pp.circumference, n_segments=pp.n_segments, 137 | s=pp.s, name=pp.name, 138 | alpha_x=pp.alpha_x, beta_x=pp.beta_x, D_x=pp.D_x, alpha_y=pp.alpha_y, beta_y=pp.beta_y, D_y=pp.D_y, 139 | accQ_x=pp.accQ_x, accQ_y=pp.accQ_y, Qp_x=pp.Qp_x, Qp_y=pp.Qp_y, app_x=pp.app_x, app_y=pp.app_y, app_xy=pp.app_xy, 140 | alpha_mom_compaction=pp.alpha, longitudinal_mode=pp.longitudinal_mode, 141 | h_RF=np.atleast_1d(pp.h_RF), V_RF=np.atleast_1d(pp.V_RF), dphi_RF=np.atleast_1d(pp.dphi_RF), 142 | p0=pp.p0, p_increment=pp.p_increment, 143 | charge=pp.charge, mass=pp.mass, RF_at=pp.RF_at) 144 | 145 | 146 | def _anharmonicities_from_octupole_current_settings(self, i_octupole_focusing, i_octupole_defocusing): 147 | """Calculate the constants of proportionality app_x, app_y and 148 | app_xy (== app_yx) for the amplitude detuning introduced by the 149 | LHC octupole magnets (aka. LHC Landau octupoles) from the 150 | electric currents i_octupole_focusing [A] and i_octupole_defocusing [A] flowing 151 | through the magnets. The maximum current is given by 152 | i_max = +/- 550 [A]. The values app_x, app_y, app_xy obtained 153 | from the formulae are proportional to the strength of detuning 154 | for one complete turn around the accelerator, i.e. one-turn 155 | values. 156 | The calculation is based on formulae (3.6) taken from 'The LHC 157 | transverse coupled-bunch instability' by N. Mounet, EPFL PhD 158 | Thesis, 2012. Values (hard-coded numbers below) are valid for 159 | LHC Landau octupoles before LS1. Beta functions in x and y are 160 | correctly taken into account. Note that here, the values of 161 | app_x, app_y and app_xy are not normalized to the reference 162 | momentum p0. This is done only during the calculation of the 163 | detuning in the corresponding detune method of the 164 | AmplitudeDetuningSegment. 165 | More detailed explanations and references on how the formulae 166 | were obtained are given in the PhD thesis (pg. 85ff) cited 167 | above. 168 | """ 169 | i_max = 550. # [A] 170 | E_max = 7000. # [GeV] 171 | 172 | app_x = E_max * (267065. * i_octupole_focusing / i_max - 173 | 7856. * i_octupole_defocusing / i_max) 174 | app_y = E_max * (9789. * i_octupole_focusing / i_max - 175 | 277203. * i_octupole_defocusing / i_max) 176 | app_xy = E_max * (-102261. * i_octupole_focusing / i_max + 177 | 93331. * i_octupole_defocusing / i_max) 178 | 179 | # Convert to SI units. 180 | convert_to_SI = e / (1.e-9 * c) 181 | app_x *= convert_to_SI 182 | app_y *= convert_to_SI 183 | app_xy *= convert_to_SI 184 | 185 | return app_x, app_y, app_xy 186 | 187 | def _octupole_currents_from_octupole_knobs(self, octupole_knob, p0): 188 | i_octupole_focusing = 19.557 * octupole_knob / (-1.5) * p0 / 2.4049285931335872e-16 189 | i_octupole_defocusing = - i_octupole_focusing 190 | return i_octupole_focusing, i_octupole_defocusing 191 | --------------------------------------------------------------------------------