Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
M
mbtrack2
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Deploy
Releases
Package registry
Model registry
Operate
Terraform modules
Analyze
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
PA
Collective Effects
mbtrack2
Commits
ac15e7e6
Commit
ac15e7e6
authored
Nov 12, 2020
by
Gamelin Alexis
Browse files
Options
Downloads
Plain Diff
Merge branch 'numpy_bunch'
parents
e32bfaf0
c670561f
No related branches found
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
tracking/particles.py
+81
-48
81 additions, 48 deletions
tracking/particles.py
tracking/wakepotential.py
+4
-3
4 additions, 3 deletions
tracking/wakepotential.py
with
85 additions
and
51 deletions
tracking/particles.py
+
81
−
48
View file @
ac15e7e6
...
@@ -8,15 +8,15 @@ Module where particles, bunches and beams are described as objects.
...
@@ -8,15 +8,15 @@ Module where particles, bunches and beams are described as objects.
"""
"""
import
numpy
as
np
import
numpy
as
np
import
pandas
as
pd
import
matplotlib.pyplot
as
plt
import
matplotlib.pyplot
as
plt
from
mbtrack2.tracking.parallel
import
Mpi
import
seaborn
as
sns
import
seaborn
as
sns
import
pandas
as
pd
from
mbtrack2.tracking.parallel
import
Mpi
from
scipy.constants
import
c
,
m_e
,
m_p
,
e
from
scipy.constants
import
c
,
m_e
,
m_p
,
e
class
Particle
:
class
Particle
:
"""
"""
Define a particle object
Define a particle object
.
Attributes
Attributes
----------
----------
...
@@ -47,35 +47,41 @@ class Proton(Particle):
...
@@ -47,35 +47,41 @@ class Proton(Particle):
class
Bunch
:
class
Bunch
:
"""
"""
Define a bunch
Define a bunch
object.
Parameters
Parameters
----------
----------
ring : Synchrotron object
ring : Synchrotron object
mp_number : float, optional
mp_number : float, optional
Macro-particle number
Macro-particle number
.
current : float, optional
current : float, optional
Bunch current in [A]
Bunch current in [A].
track_alive : bool, optional
If False, the code no longer take into account alive/dead particles.
Should be set to True if element such as apertures are used.
Can be set to False to gain a speed increase.
alive : bool, optional
alive : bool, optional
If False, the bunch is defined as empty
If False, the bunch is defined as empty
.
Attributes
Attributes
----------
----------
mp_number : int
mp_number : int
Macro-particle number
Macro-particle number.
alive : array of bool of shape (mp_number,)
Array used to monitor which particle is dead or alive.
charge : float
charge : float
Bunch charge in [C]
Bunch charge in [C]
.
charge_per_mp : float
charge_per_mp : float
Charge per macro-particle in [C]
Charge per macro-particle in [C]
.
particle_number : int
particle_number : int
Number of particles in the bunch
Number of particles in the bunch
.
current : float
current : float
Bunch current in [A]
Bunch current in [A]
.
mean : array of shape (6,)
mean : array of shape (6,)
Mean position of alive particles for each coordinates
Mean position of alive particles for each coordinates
.
std : array of shape (6,)
std : array of shape (6,)
Standard deviation of the position of alive particles for each
Standard deviation of the position of alive particles for each
coordinates
coordinates
.
emit : array of shape (3,)
emit : array of shape (3,)
Bunch emittance for each plane [1]. !!! -> Correct for long ?
Bunch emittance for each plane [1]. !!! -> Correct for long ?
energy_change : series of shape (alive,)
energy_change : series of shape (alive,)
...
@@ -97,7 +103,8 @@ class Bunch:
...
@@ -97,7 +103,8 @@ class Bunch:
Springer, Eq.(8.39) of p224.
Springer, Eq.(8.39) of p224.
"""
"""
def
__init__
(
self
,
ring
,
mp_number
=
1e3
,
current
=
1e-3
,
alive
=
True
):
def
__init__
(
self
,
ring
,
mp_number
=
1e3
,
current
=
1e-3
,
track_alive
=
True
,
alive
=
True
):
self
.
ring
=
ring
self
.
ring
=
ring
if
not
alive
:
if
not
alive
:
...
@@ -105,20 +112,22 @@ class Bunch:
...
@@ -105,20 +112,22 @@ class Bunch:
current
=
0
current
=
0
self
.
_mp_number
=
int
(
mp_number
)
self
.
_mp_number
=
int
(
mp_number
)
particles
=
{
"
x
"
:
np
.
zeros
((
self
.
mp_number
,)),
self
.
dtype
=
np
.
dtype
([(
'
x
'
,
np
.
float
),
"
xp
"
:
np
.
zeros
((
self
.
mp_number
,)),
(
'
xp
'
,
np
.
float
),
"
y
"
:
np
.
zeros
((
self
.
mp_number
,)),
(
'
y
'
,
np
.
float
),
"
yp
"
:
np
.
zeros
((
self
.
mp_number
,)),
(
'
yp
'
,
np
.
float
),
"
tau
"
:
np
.
zeros
((
self
.
mp_number
,)),
(
'
tau
'
,
np
.
float
),
"
delta
"
:
np
.
zeros
((
self
.
mp_number
,)),
(
'
delta
'
,
np
.
float
)])
}
self
.
particles
=
pd
.
DataFrame
(
particles
)
self
.
particles
=
np
.
zeros
(
self
.
mp_number
,
self
.
dtype
)
self
.
alive
=
pd
.
Series
(
np
.
ones
((
self
.
mp_number
,),
dtype
=
bool
))
self
.
track_alive
=
track_alive
self
.
alive
=
np
.
ones
((
self
.
mp_number
,),
dtype
=
bool
)
self
.
current
=
current
self
.
current
=
current
if
not
alive
:
if
not
alive
:
self
.
alive
=
pd
.
Series
(
np
.
zeros
((
self
.
mp_number
,),
dtype
=
bool
)
)
self
.
alive
=
np
.
zeros
((
self
.
mp_number
,),
dtype
=
bool
)
self
.
_energy_change
=
pd
.
Series
(
np
.
zeros
((
self
.
mp_number
,),
dtype
=
float
)
)
self
.
_energy_change
=
np
.
zeros
((
self
.
mp_number
,),
dtype
=
float
)
def
__len__
(
self
):
def
__len__
(
self
):
"""
Return the number of alive particles
"""
"""
Return the number of alive particles
"""
...
@@ -126,19 +135,25 @@ class Bunch:
...
@@ -126,19 +135,25 @@ class Bunch:
def
__getitem__
(
self
,
label
):
def
__getitem__
(
self
,
label
):
"""
Return the columns label for alive particles
"""
"""
Return the columns label for alive particles
"""
return
self
.
particles
.
loc
[
self
.
alive
,
label
]
if
self
.
track_alive
is
True
:
return
self
.
particles
[
label
][
self
.
alive
]
else
:
return
self
.
particles
[
label
]
def
__setitem__
(
self
,
label
,
value
):
def
__setitem__
(
self
,
label
,
value
):
"""
Set value to the columns label for alive particles
"""
"""
Set value to the columns label for alive particles
"""
self
.
particles
.
loc
[
self
.
alive
,
label
]
=
value
if
self
.
track_alive
is
True
:
self
.
particles
[
label
][
self
.
alive
]
=
value
else
:
self
.
particles
[
label
]
=
value
def
__iter__
(
self
):
def
__iter__
(
self
):
"""
Iterate over labels
"""
"""
Iterate over labels
"""
return
self
[:]
.
__iter__
()
return
self
.
dtype
.
names
.
__iter__
()
def
__repr__
(
self
):
def
__repr__
(
self
):
"""
Return representation of alive particles
"""
"""
Return representation of alive particles
"""
return
f
'
{
self
[
:
]
!r}
'
return
f
'
{
pd
.
DataFrame
(
self
[
:
]
)
!r}
'
@property
@property
def
mp_number
(
self
):
def
mp_number
(
self
):
...
@@ -222,11 +237,17 @@ class Bunch:
...
@@ -222,11 +237,17 @@ class Bunch:
the SynchrotronRadiation class to compute radiation damping. To be
the SynchrotronRadiation class to compute radiation damping. To be
changed by Element objects which change the energy, for example RF
changed by Element objects which change the energy, for example RF
cavities.
"""
cavities.
"""
return
self
.
_energy_change
.
loc
[
self
.
alive
]
if
self
.
track_alive
is
True
:
return
self
.
_energy_change
[
self
.
alive
]
else
:
return
self
.
_energy_change
@energy_change.setter
@energy_change.setter
def
energy_change
(
self
,
value
):
def
energy_change
(
self
,
value
):
self
.
_energy_change
.
loc
[
self
.
alive
]
=
value
if
self
.
track_alive
is
True
:
self
.
_energy_change
[
self
.
alive
]
=
value
else
:
self
.
_energy_change
=
value
def
init_gaussian
(
self
,
cov
=
None
,
mean
=
None
,
**
kwargs
):
def
init_gaussian
(
self
,
cov
=
None
,
mean
=
None
,
**
kwargs
):
"""
"""
...
@@ -289,22 +310,28 @@ class Bunch:
...
@@ -289,22 +310,28 @@ class Bunch:
Returns
Returns
-------
-------
bins :
IntervalIndex
of shape (n_bin,)
bins :
array
of shape (n_bin,)
Bins where the particles are sorted.
Bins where the particles are sorted.
sorted_index :
Series
of shape (self.mp_number,)
sorted_index :
array
of shape (self.mp_number,)
Bin number of each macro-particles.
Bin number of each macro-particles.
profile :
Series
of shape (n_bin,)
profile :
array
of shape (n_bin
- 1
,)
Number of marco-particles in each bin.
Number of marco-particles in each bin.
center : array of shape (n_bin - 1,)
Center of each bin.
"""
"""
bins
=
pd
.
interval_range
(
start
=
min
(
self
[
dimension
]),
bin_min
=
self
[
dimension
].
min
()
end
=
max
(
self
[
dimension
]),
bin_min
=
min
(
bin_min
*
0.99
,
bin_min
*
1.01
)
periods
=
n_bin
,
bin_max
=
self
[
dimension
].
max
()
name
=
dimension
)
bin_max
=
max
(
bin_max
*
0.99
,
bin_max
*
1.01
)
sorted_index
=
pd
.
cut
(
self
[
dimension
],
bins
)
sorted_index
=
sorted_index
.
reindex
(
self
.
alive
.
index
)
bins
=
np
.
linspace
(
bin_min
,
bin_max
,
n_bin
)
profile
=
sorted_index
.
value_counts
().
sort_index
()
center
=
(
bins
[
1
:]
+
bins
[:
-
1
])
/
2
return
(
bins
,
sorted_index
,
profile
)
sorted_index
=
np
.
searchsorted
(
bins
,
self
[
dimension
],
side
=
'
left
'
)
sorted_index
-=
1
profile
=
np
.
bincount
(
sorted_index
,
minlength
=
n_bin
-
1
)
return
(
bins
,
sorted_index
,
profile
,
center
)
def
plot_profile
(
self
,
dimension
=
"
tau
"
,
n_bin
=
75
):
def
plot_profile
(
self
,
dimension
=
"
tau
"
,
n_bin
=
75
):
"""
"""
...
@@ -318,10 +345,10 @@ class Bunch:
...
@@ -318,10 +345,10 @@ class Bunch:
Number of bins. The default is 75.
Number of bins. The default is 75.
"""
"""
bins
,
sorted_index
,
profile
=
self
.
binning
(
dimension
,
n_bin
)
bins
,
sorted_index
,
profile
,
center
=
self
.
binning
(
dimension
,
n_bin
)
fig
=
plt
.
figure
()
fig
=
plt
.
figure
()
ax
=
fig
.
gca
()
ax
=
fig
.
gca
()
ax
.
plot
(
bins
.
mid
,
profile
)
ax
.
plot
(
center
,
profile
)
def
plot_phasespace
(
self
,
x_var
=
"
tau
"
,
y_var
=
"
delta
"
,
plot_type
=
"
j
"
):
def
plot_phasespace
(
self
,
x_var
=
"
tau
"
,
y_var
=
"
delta
"
,
plot_type
=
"
j
"
):
"""
"""
...
@@ -476,7 +503,7 @@ class Beam:
...
@@ -476,7 +503,7 @@ class Beam:
return
distance
return
distance
def
init_beam
(
self
,
filling_pattern
,
current_per_bunch
=
1e-3
,
def
init_beam
(
self
,
filling_pattern
,
current_per_bunch
=
1e-3
,
mp_per_bunch
=
1e3
):
mp_per_bunch
=
1e3
,
track_alive
=
True
):
"""
"""
Initialize beam with a given filling pattern and marco-particle number
Initialize beam with a given filling pattern and marco-particle number
per bunch. Then initialize the different bunches with a 6D gaussian
per bunch. Then initialize the different bunches with a 6D gaussian
...
@@ -496,6 +523,10 @@ class Beam:
...
@@ -496,6 +523,10 @@ class Beam:
Current per bunch in [A]
Current per bunch in [A]
mp_per_bunch : float, optional
mp_per_bunch : float, optional
Macro-particle number per bunch
Macro-particle number per bunch
track_alive : bool, optional
If False, the code no longer take into account alive/dead particles.
Should be set to True if element such as apertures are used.
Can be set to False to gain a speed increase.
"""
"""
if
(
len
(
filling_pattern
)
!=
self
.
ring
.
h
):
if
(
len
(
filling_pattern
)
!=
self
.
ring
.
h
):
...
@@ -507,13 +538,15 @@ class Beam:
...
@@ -507,13 +538,15 @@ class Beam:
if
filling_pattern
.
dtype
==
np
.
dtype
(
"
bool
"
):
if
filling_pattern
.
dtype
==
np
.
dtype
(
"
bool
"
):
for
value
in
filling_pattern
:
for
value
in
filling_pattern
:
if
value
==
True
:
if
value
==
True
:
bunch_list
.
append
(
Bunch
(
self
.
ring
,
mp_per_bunch
,
current_per_bunch
))
bunch_list
.
append
(
Bunch
(
self
.
ring
,
mp_per_bunch
,
current_per_bunch
,
track_alive
))
elif
value
==
False
:
elif
value
==
False
:
bunch_list
.
append
(
Bunch
(
self
.
ring
,
alive
=
False
))
bunch_list
.
append
(
Bunch
(
self
.
ring
,
alive
=
False
))
elif
filling_pattern
.
dtype
==
np
.
dtype
(
"
float64
"
):
elif
filling_pattern
.
dtype
==
np
.
dtype
(
"
float64
"
):
for
current
in
filling_pattern
:
for
current
in
filling_pattern
:
if
current
!=
0
:
if
current
!=
0
:
bunch_list
.
append
(
Bunch
(
self
.
ring
,
mp_per_bunch
,
current
))
bunch_list
.
append
(
Bunch
(
self
.
ring
,
mp_per_bunch
,
current_per_bunch
,
track_alive
))
elif
current
==
0
:
elif
current
==
0
:
bunch_list
.
append
(
Bunch
(
self
.
ring
,
alive
=
False
))
bunch_list
.
append
(
Bunch
(
self
.
ring
,
alive
=
False
))
else
:
else
:
...
...
This diff is collapsed.
Click to expand it.
tracking/wakepotential.py
+
4
−
3
View file @
ac15e7e6
...
@@ -85,18 +85,19 @@ class WakePotential(Element):
...
@@ -85,18 +85,19 @@ class WakePotential(Element):
"""
"""
# Get binning data
# Get binning data
a
,
b
,
c
=
bunch
.
binning
(
n_bin
=
self
.
n_bin
)
a
,
b
,
c
,
d
=
bunch
.
binning
(
n_bin
=
self
.
n_bin
)
self
.
bins
=
a
self
.
bins
=
a
self
.
sorted_index
=
b
self
.
sorted_index
=
b
self
.
profile
=
c
self
.
profile
=
c
self
.
bin_size
=
self
.
bins
.
length
self
.
center
=
d
self
.
bin_size
=
self
.
bins
[
1
]
-
self
.
bins
[
0
]
# Compute charge density
# Compute charge density
self
.
rho
=
bunch
.
charge_per_mp
*
self
.
profile
/
(
self
.
bin_size
*
bunch
.
charge
)
self
.
rho
=
bunch
.
charge_per_mp
*
self
.
profile
/
(
self
.
bin_size
*
bunch
.
charge
)
self
.
rho
=
np
.
array
(
self
.
rho
)
self
.
rho
=
np
.
array
(
self
.
rho
)
# Compute time array
# Compute time array
self
.
tau
=
np
.
array
(
self
.
bins
.
mid
)
self
.
tau
=
np
.
array
(
self
.
center
)
self
.
dtau
=
self
.
tau
[
1
]
-
self
.
tau
[
0
]
self
.
dtau
=
self
.
tau
[
1
]
-
self
.
tau
[
0
]
# Add N values before and after rho and tau
# Add N values before and after rho and tau
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment