pypic-poisson 2.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pypic_poisson-2.5.0/MANIFEST.in +5 -0
- pypic_poisson-2.5.0/Makefile +7 -0
- pypic_poisson-2.5.0/PKG-INFO +113 -0
- pypic_poisson-2.5.0/PyPIC/Bassetti_Erskine.py +193 -0
- pypic_poisson-2.5.0/PyPIC/FFT_OpenBoundary.py +257 -0
- pypic_poisson-2.5.0/PyPIC/FFT_OpenBoundary_SquareGrid.py +59 -0
- pypic_poisson-2.5.0/PyPIC/FFT_PEC_Boundary_SquareGrid.py +188 -0
- pypic_poisson-2.5.0/PyPIC/FiniteDifferences_ShortleyWeller_SquareGrid.py +339 -0
- pypic_poisson-2.5.0/PyPIC/FiniteDifferences_ShortleyWeller_SquareGrid_extrapolation.py +466 -0
- pypic_poisson-2.5.0/PyPIC/FiniteDifferences_Staircase_SquareGrid.py +266 -0
- pypic_poisson-2.5.0/PyPIC/MultiGrid.py +303 -0
- pypic_poisson-2.5.0/PyPIC/PyPIC_Scatter_Gather.py +212 -0
- pypic_poisson-2.5.0/PyPIC/__init__.py +1 -0
- pypic_poisson-2.5.0/PyPIC/_version.py +1 -0
- pypic_poisson-2.5.0/PyPIC/fortran/compute_rho.f +65 -0
- pypic_poisson-2.5.0/PyPIC/fortran/errfff.f +105 -0
- pypic_poisson-2.5.0/PyPIC/fortran/interp_field_for.f +61 -0
- pypic_poisson-2.5.0/PyPIC/fortran/interp_field_for_with_border.f +107 -0
- pypic_poisson-2.5.0/PyPIC/geom_impact_ellip.py +209 -0
- pypic_poisson-2.5.0/PyPIC/geom_impact_poly.py +296 -0
- pypic_poisson-2.5.0/PyPIC/myloadmat_to_obj.py +20 -0
- pypic_poisson-2.5.0/PyPIC/mystyle.py +381 -0
- pypic_poisson-2.5.0/PyPIC/simple_polygon.py +58 -0
- pypic_poisson-2.5.0/README.md +97 -0
- pypic_poisson-2.5.0/examples/cpu/000_test_round_chamber.py +93 -0
- pypic_poisson-2.5.0/examples/cpu/002_test_rect_chamber.py +120 -0
- pypic_poisson-2.5.0/examples/cpu/003_Xmas_tree.py +125 -0
- pypic_poisson-2.5.0/examples/cpu/004_test_gaussian.py +53 -0
- pypic_poisson-2.5.0/examples/cpu/005_testfftw.py +43 -0
- pypic_poisson-2.5.0/examples/cpu/006_time_solve.py +99 -0
- pypic_poisson-2.5.0/examples/cpu/007_test_separately.py +107 -0
- pypic_poisson-2.5.0/examples/cpu/008a_check_interpolation_near_borders.py +50 -0
- pypic_poisson-2.5.0/examples/cpu/008b_check_interpolation_near_borders_plots.py +190 -0
- pypic_poisson-2.5.0/examples/cpu/009_test_round_chamber_for_new_interp_devel.py +68 -0
- pypic_poisson-2.5.0/examples/cpu/010_effect_of_tolerances_in_SW.py +98 -0
- pypic_poisson-2.5.0/examples/cpu/011_LHC_multigrid_test.py +293 -0
- pypic_poisson-2.5.0/examples/cpu/012_test_states.py +119 -0
- pypic_poisson-2.5.0/examples/cpu/LHC.py +190 -0
- pypic_poisson-2.5.0/examples/cpu/README.md +50 -0
- pypic_poisson-2.5.0/pypic_poisson.egg-info/PKG-INFO +113 -0
- pypic_poisson-2.5.0/pypic_poisson.egg-info/SOURCES.txt +47 -0
- pypic_poisson-2.5.0/pypic_poisson.egg-info/dependency_links.txt +1 -0
- pypic_poisson-2.5.0/pypic_poisson.egg-info/requires.txt +11 -0
- pypic_poisson-2.5.0/pypic_poisson.egg-info/top_level.txt +1 -0
- pypic_poisson-2.5.0/pyproject.toml +33 -0
- pypic_poisson-2.5.0/release.py +101 -0
- pypic_poisson-2.5.0/setup.cfg +4 -0
- pypic_poisson-2.5.0/setup.py +51 -0
- pypic_poisson-2.5.0/tests/test_native.py +79 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pypic-poisson
|
|
3
|
+
Version: 2.5.0
|
|
4
|
+
Summary: Collection of Python Particle-In-Cell solvers
|
|
5
|
+
Project-URL: Source Code, https://github.com/PyCOMPLETE/PyPIC
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: numpy>=1.26
|
|
9
|
+
Requires-Dist: scipy
|
|
10
|
+
Provides-Extra: tests
|
|
11
|
+
Requires-Dist: pytest; extra == "tests"
|
|
12
|
+
Provides-Extra: examples
|
|
13
|
+
Requires-Dist: matplotlib; extra == "examples"
|
|
14
|
+
Provides-Extra: fftw
|
|
15
|
+
Requires-Dist: pyfftw; extra == "fftw"
|
|
16
|
+
|
|
17
|
+
# PyPIC
|
|
18
|
+
|
|
19
|
+
Particle-in-cell solvers for beam simulations. The repository contains the
|
|
20
|
+
`PyPIC` Python package, native Fortran sources, tests, and examples.
|
|
21
|
+
Existing imports such as `from PyPIC.MultiGrid import AddTelescopicGrids` remain
|
|
22
|
+
unchanged.
|
|
23
|
+
The PyPI distribution is named **pypic-poisson**; the unrelated `pypic`
|
|
24
|
+
distribution on PyPI is not this project.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
Python 3.11 or newer and working C and Fortran compilers are required. For example,
|
|
29
|
+
in a conda environment install `c-compiler` and `fortran-compiler` from conda-forge,
|
|
30
|
+
then activate that environment so its compiler settings are available.
|
|
31
|
+
|
|
32
|
+
Install the released package with:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
python -m pip install pypic-poisson
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Only source distributions are published: pip compiles the native extensions
|
|
39
|
+
locally. If this checkout was previously installed under the distribution name
|
|
40
|
+
`PyPIC`, uninstall that old distribution (`python -m pip uninstall PyPIC`)
|
|
41
|
+
before installing `pypic-poisson`, since both use the `PyPIC` import namespace.
|
|
42
|
+
|
|
43
|
+
For development, from the directory containing this checkout:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
python -m pip install -e ./PyPIC
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or, from inside the checkout:
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
python -m pip install -e .
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Pip installs Python build dependencies in an isolated build environment and
|
|
56
|
+
compiles all four core Fortran extensions. No manual `make` step or precompiled
|
|
57
|
+
binaries are needed. NumPy and SciPy are runtime dependencies.
|
|
58
|
+
The legacy GPU and FPPS solvers are no longer included.
|
|
59
|
+
|
|
60
|
+
Python edits take effect immediately. After changing Fortran
|
|
61
|
+
sources, rerun the installation command to rebuild the extensions. Use
|
|
62
|
+
`python -m pip install .` for a regular installation.
|
|
63
|
+
|
|
64
|
+
### Optional runtime dependencies
|
|
65
|
+
|
|
66
|
+
- `python -m pip install -e '.[fftw]'` installs the Python FFTW interface used by
|
|
67
|
+
FFT solvers.
|
|
68
|
+
- `python -m pip install -e '.[examples]'` adds matplotlib for the example scripts.
|
|
69
|
+
See [the CPU examples guide](examples/cpu/README.md) for optional dependencies
|
|
70
|
+
and instructions.
|
|
71
|
+
|
|
72
|
+
## Development and validation
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
python -m pip install -e '.[tests]'
|
|
76
|
+
python -m pytest
|
|
77
|
+
python -m pip install build
|
|
78
|
+
python -m build
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The tests check native-module imports, numerical deposition/interpolation,
|
|
82
|
+
the complex error function, and a Poisson solve.
|
|
83
|
+
`python -m build` creates a source distribution and builds a wheel from it.
|
|
84
|
+
Generated binaries are specific to the Python/platform used for the build.
|
|
85
|
+
|
|
86
|
+
Legacy CPU plotting scripts are under `examples/cpu/`; automated tests
|
|
87
|
+
are under `tests/`. The root Makefile is only a convenience wrapper around pip.
|
|
88
|
+
Package version metadata lives in `PyPIC/_version.py`.
|
|
89
|
+
|
|
90
|
+
## Publishing a source release
|
|
91
|
+
|
|
92
|
+
Set the version in `PyPIC/_version.py`, then install the release tools:
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
python -m pip install build twine
|
|
96
|
+
python release.py --build-only
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
This builds and checks one source archive in `dist/`, without uploading or
|
|
100
|
+
tagging. After testing the archive, commit and push the release changes, then run:
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
python release.py
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The script requires a clean checkout and an unused `v<version>` tag. It builds
|
|
107
|
+
and checks the source archive, uploads only that `.tar.gz` to PyPI using your
|
|
108
|
+
Twine credentials (for example, configured in `~/.pypirc`), then creates and
|
|
109
|
+
pushes the version tag to `origin`. No wheels are uploaded. If the upload
|
|
110
|
+
succeeds but tagging or pushing fails, finish those Git operations manually;
|
|
111
|
+
PyPI does not allow re-uploading the same release file.
|
|
112
|
+
|
|
113
|
+
Publish `pypic-poisson` before releasing PyECLOUD, which depends on it.
|
|
@@ -0,0 +1,193 @@
|
|
|
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
|
+
|
|
@@ -0,0 +1,257 @@
|
|
|
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
|
+
import scipy.sparse as scsp
|
|
55
|
+
from scipy.sparse.linalg import spsolve
|
|
56
|
+
import scipy.sparse.linalg as ssl
|
|
57
|
+
from .PyPIC_Scatter_Gather import PyPIC_Scatter_Gather
|
|
58
|
+
from scipy.constants import e, epsilon_0
|
|
59
|
+
|
|
60
|
+
na = lambda x:np.array([x])
|
|
61
|
+
|
|
62
|
+
qe=e
|
|
63
|
+
eps0=epsilon_0
|
|
64
|
+
|
|
65
|
+
class FFT_OpenBoundary(PyPIC_Scatter_Gather):
|
|
66
|
+
#@profile
|
|
67
|
+
def __init__(self, x_aper, y_aper, Dh=None, dx=None, dy=None, fftlib = 'pyfftw'):
|
|
68
|
+
|
|
69
|
+
print('Start PIC init.:')
|
|
70
|
+
print('FFT, Open Boundary')
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
if dx is not None and dy is not None:
|
|
74
|
+
assert(Dh is None)
|
|
75
|
+
|
|
76
|
+
elif Dh!=None:
|
|
77
|
+
assert(dx is None and dy is None)
|
|
78
|
+
dx = Dh
|
|
79
|
+
dy = Dh
|
|
80
|
+
|
|
81
|
+
else:
|
|
82
|
+
raise ValueError('Dh or dx and dy must be specified!!!')
|
|
83
|
+
|
|
84
|
+
super(FFT_OpenBoundary, self).__init__(x_aper, y_aper, dx, dy)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
nx = len(self.xg)
|
|
88
|
+
ny = len(self.yg)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
mx = -dx / 2 + np.arange(nx + 1) * dx
|
|
92
|
+
my = -dy / 2 + np.arange(ny + 1) * dy
|
|
93
|
+
x, y = np.meshgrid(mx, my)
|
|
94
|
+
r2 = x ** 2 + y ** 2
|
|
95
|
+
# Antiderivative
|
|
96
|
+
tmpfgreen = -(-3 * x * y + x * y * np.log(r2)
|
|
97
|
+
+ x * x * np.arctan(y / x) + y * y * np.arctan(x / y)) # * 2 / dx / dy
|
|
98
|
+
|
|
99
|
+
fgreen = np.zeros((2 * ny, 2 * nx))
|
|
100
|
+
# Integration and circular Green's function
|
|
101
|
+
fgreen[:ny, :nx] = tmpfgreen[1:, 1:] + tmpfgreen[:-1, :-1] - tmpfgreen[1:, :-1] - tmpfgreen[:-1, 1:]
|
|
102
|
+
fgreen[ny:, :nx] = fgreen[ny:0:-1, :nx]
|
|
103
|
+
fgreen[:ny, nx:] = fgreen[:ny, nx:0:-1]
|
|
104
|
+
fgreen[ny:, nx:] = fgreen[ny:0:-1, nx:0:-1]
|
|
105
|
+
|
|
106
|
+
self.fgreen = fgreen
|
|
107
|
+
self.fgreentr = np.fft.fft2(fgreen).copy()
|
|
108
|
+
|
|
109
|
+
if fftlib == 'pyfftw':
|
|
110
|
+
try:
|
|
111
|
+
import pyfftw
|
|
112
|
+
print('Using PyFFTW')
|
|
113
|
+
#prepare fftw's
|
|
114
|
+
|
|
115
|
+
self.tmprho = (fgreen*(1.+1j))*0.
|
|
116
|
+
fft_first = pyfftw.builders.fft(self.tmprho[:ny, :], axis = 1, threads = 1)
|
|
117
|
+
|
|
118
|
+
self.tmpfft = (fgreen*(1.+1j))*0.
|
|
119
|
+
self.tmpfft[:ny, :] = fft_first(self.tmprho[:ny, :])
|
|
120
|
+
fft_second = pyfftw.builders.fft(self.tmpfft, axis = 0, threads = 1)
|
|
121
|
+
|
|
122
|
+
self.phifft = fft_second(self.tmpfft) * self.fgreentr
|
|
123
|
+
ifft_first = pyfftw.builders.ifft(self.phifft, axis = 0, threads = 1)
|
|
124
|
+
|
|
125
|
+
self.tmpifft = ifft_first(self.phifft)
|
|
126
|
+
ifft_second = pyfftw.builders.ifft(self.tmpifft[:ny, :], axis = 1, threads = 1)
|
|
127
|
+
self.tmpphi = (self.fgreen*(1.+1j))*0.
|
|
128
|
+
|
|
129
|
+
#@profile
|
|
130
|
+
def fft2_pyfftw():
|
|
131
|
+
self.tmpfft[:ny, :] = fft_first(self.tmprho[:ny, :])
|
|
132
|
+
self.phifft = fft_second(self.tmpfft) * self.fgreentr
|
|
133
|
+
self.tmpifft = ifft_first(self.phifft)
|
|
134
|
+
self.tmpphi[:ny, :] = ifft_second(self.tmpifft[:ny, :])
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
self.fft2 = fft2_pyfftw
|
|
138
|
+
|
|
139
|
+
self.tmpfft = (self.fgreen*(1.+1j))*0.
|
|
140
|
+
self.tmpifft = (self.fgreen*(1.+1j))*0.
|
|
141
|
+
|
|
142
|
+
except ImportError as err:
|
|
143
|
+
print('Failed to import pyfftw')
|
|
144
|
+
print('Got exception: ', err)
|
|
145
|
+
|
|
146
|
+
fftlib = 'numpy'
|
|
147
|
+
|
|
148
|
+
if fftlib == 'numpy':
|
|
149
|
+
print('Using numpy FFT')
|
|
150
|
+
|
|
151
|
+
self.tmprho = (self.fgreen*(1.+1j))*0.
|
|
152
|
+
self.tmpphi = (self.fgreen*(1.+1j))*0.
|
|
153
|
+
|
|
154
|
+
def fft2_numpy():
|
|
155
|
+
self.phifft = np.fft.fft2(self.tmprho) * self.fgreentr
|
|
156
|
+
self.tmpphi = np.fft.ifft2(self.phifft)
|
|
157
|
+
|
|
158
|
+
self.fft2 = fft2_numpy
|
|
159
|
+
|
|
160
|
+
elif fftlib != 'pyfftw':
|
|
161
|
+
raise ValueError('fftlib not recognized!!!!')
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
self.rho = np.zeros((self.Nxg,self.Nyg))
|
|
165
|
+
self.phi = np.zeros((self.Nxg,self.Nyg))
|
|
166
|
+
self.efx = np.zeros((self.Nxg,self.Nyg))
|
|
167
|
+
self.efy = np.zeros((self.Nxg,self.Nyg))
|
|
168
|
+
|
|
169
|
+
self.hlpphi = (self.phi*(1.+1j))*0.
|
|
170
|
+
self.hlpefx = (self.efx*(1.+1j))*0.
|
|
171
|
+
self.hlpefy = (self.efy*(1.+1j))*0.
|
|
172
|
+
|
|
173
|
+
self.tmprho = (self.fgreen*(1.+1j))*0.
|
|
174
|
+
self.tmpphi = (self.fgreen*(1.+1j))*0.
|
|
175
|
+
|
|
176
|
+
self.Dh = Dh
|
|
177
|
+
self.nx = nx
|
|
178
|
+
self.ny = ny
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
#@profile
|
|
182
|
+
def solve(self, rho = None, flag_verbose = False):
|
|
183
|
+
if rho is None:
|
|
184
|
+
rho = self.rho
|
|
185
|
+
|
|
186
|
+
self._solve_core(rho)
|
|
187
|
+
|
|
188
|
+
self.phi = np.real(self.hlpphi)
|
|
189
|
+
self.efx = np.real(self.hlpefx)
|
|
190
|
+
self.efy = np.real(self.hlpefy)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def get_state_object(self):
|
|
194
|
+
state = PyPIC_Scatter_Gather(xg = self.xg, yg = self.yg)
|
|
195
|
+
|
|
196
|
+
state.rho = self.rho.copy()
|
|
197
|
+
state.phi = self.phi.copy()
|
|
198
|
+
state.efx = self.efx.copy()
|
|
199
|
+
state.efy = self.efy.copy()
|
|
200
|
+
|
|
201
|
+
return state
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
#~ def load_state_object(self, state):
|
|
205
|
+
#~ self.rho = state.rho.copy()
|
|
206
|
+
#~ self.phi = state.phi.copy()
|
|
207
|
+
#~ self.efx = state.efx.copy()
|
|
208
|
+
#~ self.efy = state.efy.copy()
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
#@profile
|
|
212
|
+
def solve_states(self, states):
|
|
213
|
+
|
|
214
|
+
states = np.atleast_1d(states)
|
|
215
|
+
|
|
216
|
+
if len(states) > 2:
|
|
217
|
+
raise ValueError('Not implemented yet! Sorry.')
|
|
218
|
+
|
|
219
|
+
elif len(states) == 1:
|
|
220
|
+
|
|
221
|
+
state = states[0]
|
|
222
|
+
|
|
223
|
+
self._solve_core(state.rho)
|
|
224
|
+
|
|
225
|
+
state.phi = np.real(self.hlpphi)
|
|
226
|
+
state.efx = np.real(self.hlpefx)
|
|
227
|
+
state.efy = np.real(self.hlpefy)
|
|
228
|
+
|
|
229
|
+
else:
|
|
230
|
+
rho = 1*states[0].rho + 1j*states[1].rho
|
|
231
|
+
|
|
232
|
+
self._solve_core(rho)
|
|
233
|
+
|
|
234
|
+
states[1].phi = np.imag(self.hlpphi)
|
|
235
|
+
states[1].efx = np.imag(self.hlpefx)
|
|
236
|
+
states[1].efy = np.imag(self.hlpefy)
|
|
237
|
+
states[0].phi = np.real(self.hlpphi)
|
|
238
|
+
states[0].efx = np.real(self.hlpefx)
|
|
239
|
+
states[0].efy = np.real(self.hlpefy)
|
|
240
|
+
|
|
241
|
+
#@profile
|
|
242
|
+
def _solve_core(self, rho):
|
|
243
|
+
|
|
244
|
+
self.tmprho[:self.ny, :self.nx] = rho.T
|
|
245
|
+
|
|
246
|
+
self.fft2()
|
|
247
|
+
|
|
248
|
+
self.hlpphi = 1./(4. * np.pi * eps0)*(self.tmpphi[:self.ny, :self.nx]).T
|
|
249
|
+
|
|
250
|
+
self.hlpefx[1:self.Nxg-1,:] = self.hlpphi[0:self.Nxg-2,:] - self.hlpphi[2:self.Nxg,:]; #central difference on internal nodes
|
|
251
|
+
self.hlpefy[:,1:self.Nyg-1] = self.hlpphi[:,0:self.Nyg-2] - self.hlpphi[:,2:self.Nyg]; #central difference on internal nodes
|
|
252
|
+
|
|
253
|
+
self.hlpefx = self.hlpefx/(2*self.dx)
|
|
254
|
+
self.hlpefy = self.hlpefy/(2*self.dy)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
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
|
+
|