pySRU 0.5.5__py3-none-any.whl
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.
- pySRU/ElectricalField.py +59 -0
- pySRU/ElectronBeam.py +67 -0
- pySRU/MagneticField.py +146 -0
- pySRU/MagneticStructure.py +133 -0
- pySRU/MagneticStructureBendingMagnet.py +114 -0
- pySRU/MagneticStructureUndulatorPlane.py +145 -0
- pySRU/Radiation.py +289 -0
- pySRU/RadiationFactory.py +641 -0
- pySRU/Simulation.py +954 -0
- pySRU/Source.py +153 -0
- pySRU/SourceBendingmagnet.py +189 -0
- pySRU/SourceUndulatorPlane.py +286 -0
- pySRU/Trajectory.py +387 -0
- pySRU/TrajectoryFactory.py +269 -0
- pySRU/__init__.py +0 -0
- pySRU/main.py +147 -0
- pySRU/tests/AllTests.py +34 -0
- pySRU/tests/MagneticFieldTest.py +120 -0
- pySRU/tests/MagneticStructureTest.py +70 -0
- pySRU/tests/MainTest.py +136 -0
- pySRU/tests/RadiationFactorytest.py +83 -0
- pySRU/tests/RadiationTest.py +131 -0
- pySRU/tests/SimulationTest.py +108 -0
- pySRU/tests/SourceTest.py +62 -0
- pySRU/tests/TrajectoryFactoryTest.py +74 -0
- pySRU/tests/TrajectoryTest.py +64 -0
- pySRU/tests/__init__.py +2 -0
- pysru-0.5.5.dist-info/METADATA +16 -0
- pysru-0.5.5.dist-info/RECORD +32 -0
- pysru-0.5.5.dist-info/WHEEL +5 -0
- pysru-0.5.5.dist-info/licenses/LICENSE +21 -0
- pysru-0.5.5.dist-info/top_level.txt +1 -0
pySRU/ElectricalField.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# /*##########################################################################
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2016 European Synchrotron Radiation Facility
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
# furnished to do so, subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
|
14
|
+
# all copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
# THE SOFTWARE.
|
|
23
|
+
#
|
|
24
|
+
# ###########################################################################*/
|
|
25
|
+
|
|
26
|
+
__authors__ = ["S Thery, M Glass, M Sanchez del Rio - ESRF ISDD Advanced Analysis and Modelling"]
|
|
27
|
+
__license__ = "MIT"
|
|
28
|
+
__date__ = "31/08/2016"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
import numpy as np
|
|
32
|
+
class ElectricalField(object):
|
|
33
|
+
def __init__(self, electrical_field, X, Y, distance):
|
|
34
|
+
# TODO: maybe check constants if we just calcualte vector potential A
|
|
35
|
+
self._electrical_field = electrical_field.copy()
|
|
36
|
+
self._X = X.copy()
|
|
37
|
+
self._Y = Y.copy()
|
|
38
|
+
self._distance = distance
|
|
39
|
+
|
|
40
|
+
def X(self):
|
|
41
|
+
return self._X.copy()
|
|
42
|
+
|
|
43
|
+
def Y(self):
|
|
44
|
+
return self._Y.copy()
|
|
45
|
+
|
|
46
|
+
def distance(self):
|
|
47
|
+
return self._distance
|
|
48
|
+
|
|
49
|
+
def electrical_field(self):
|
|
50
|
+
return self._electrical_field.copy()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def intensity(self):
|
|
55
|
+
return np.sum(np.abs(self.electrical_field()) ** 2, axis=-1)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
pySRU/ElectronBeam.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# /*##########################################################################
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2016 European Synchrotron Radiation Facility
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
# furnished to do so, subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
|
14
|
+
# all copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
# THE SOFTWARE.
|
|
23
|
+
#
|
|
24
|
+
# ###########################################################################*/
|
|
25
|
+
|
|
26
|
+
__authors__ = ["S Thery, M Glass, M Sanchez del Rio - ESRF ISDD Advanced Analysis and Modelling"]
|
|
27
|
+
__license__ = "MIT"
|
|
28
|
+
__date__ = "31/08/2016"
|
|
29
|
+
|
|
30
|
+
import numpy as np
|
|
31
|
+
import scipy.constants as codata
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# container class
|
|
35
|
+
# parameter of the beam
|
|
36
|
+
class ElectronBeam(object):
|
|
37
|
+
def __init__(self, Electron_energy, I_current):
|
|
38
|
+
self.Electron_energy=Electron_energy
|
|
39
|
+
self.I_current=I_current
|
|
40
|
+
|
|
41
|
+
def copy(self):
|
|
42
|
+
return ElectronBeam(Electron_energy=self.Electron_energy, I_current=self.I_current)
|
|
43
|
+
|
|
44
|
+
def Lorentz_factor(self):
|
|
45
|
+
return 1e9*self.Electron_energy / (codata.m_e * codata.c**2 / codata.e)
|
|
46
|
+
|
|
47
|
+
def electron_speed(self):
|
|
48
|
+
gamma = self.Lorentz_factor()
|
|
49
|
+
Beta = np.sqrt(1.0 - 1.0 / gamma ** 2)
|
|
50
|
+
return Beta
|
|
51
|
+
|
|
52
|
+
def print_parameters(self):
|
|
53
|
+
print(' Electron Beam')
|
|
54
|
+
print(' Electron energy (GeV): %.3f' %self.Electron_energy)
|
|
55
|
+
print(' Intensity (A): %.3f' % self.I_current)
|
|
56
|
+
print(' Electron speed : %.10f' %self.electron_speed())
|
|
57
|
+
print(' Lorentz factor : %.7f' % self.Lorentz_factor())
|
|
58
|
+
|
|
59
|
+
if __name__ == "__main__" :
|
|
60
|
+
K = 1.87
|
|
61
|
+
E = 1.3
|
|
62
|
+
I = 1.0
|
|
63
|
+
beam=ElectronBeam(Electron_energy=E, I_current=I)
|
|
64
|
+
|
|
65
|
+
beam.print_parameters()
|
|
66
|
+
|
|
67
|
+
print('Lorentz factor: %f'%beam.Lorentz_factor())
|
pySRU/MagneticField.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# /*##########################################################################
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2016 European Synchrotron Radiation Facility
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
# furnished to do so, subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
|
14
|
+
# all copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
# THE SOFTWARE.
|
|
23
|
+
#
|
|
24
|
+
# ###########################################################################*/
|
|
25
|
+
|
|
26
|
+
__authors__ = ["S Thery, M Glass, M Sanchez del Rio - ESRF ISDD Advanced Analysis and Modelling"]
|
|
27
|
+
__license__ = "MIT"
|
|
28
|
+
__date__ = "31/08/2016"
|
|
29
|
+
|
|
30
|
+
import numpy as np
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class MagneticField(object):
|
|
37
|
+
def __init__(self,Bx,By,Bz):
|
|
38
|
+
self.Bx = Bx
|
|
39
|
+
self.By = By
|
|
40
|
+
self.Bz = Bz
|
|
41
|
+
|
|
42
|
+
def copy(self):
|
|
43
|
+
if type(self.Bx)==np.ndarray:
|
|
44
|
+
Bx = self.Bx.copy()
|
|
45
|
+
else :
|
|
46
|
+
Bx=self.Bx
|
|
47
|
+
if type(self.By)==np.ndarray:
|
|
48
|
+
By = self.By.copy()
|
|
49
|
+
else :
|
|
50
|
+
By=self.By
|
|
51
|
+
if type(self.Bz)==np.ndarray:
|
|
52
|
+
Bz = self.Bz.copy()
|
|
53
|
+
else :
|
|
54
|
+
Bz=self.Bz
|
|
55
|
+
return MagneticField(Bx=Bx, By=By, Bz=Bz)
|
|
56
|
+
|
|
57
|
+
#faire une fct aui fait l'interpolation et elargissement
|
|
58
|
+
#
|
|
59
|
+
|
|
60
|
+
#TODO a modifier
|
|
61
|
+
# enelarge 2 vector for the interpolation of the magnetic field use in trajectory_undulator_from_magnetic_field2
|
|
62
|
+
def enlargement_vector_for_interpolation(self,Z,Y ,nb_enlarg=0):
|
|
63
|
+
dz = Z[1] -Z[0]
|
|
64
|
+
enlarg_1 = np.linspace(Z[0] - nb_enlarg * dz, Z[0] - dz, nb_enlarg)
|
|
65
|
+
enlarg_2 = np.linspace(Z[- 1] + dz, Z[- 1] + nb_enlarg * dz, nb_enlarg)
|
|
66
|
+
Z = np.concatenate((enlarg_1, Z))
|
|
67
|
+
Z = np.concatenate((Z, enlarg_2))
|
|
68
|
+
if (type(Y )==np.ndarray) :
|
|
69
|
+
dy = Y [1] - Y [0]
|
|
70
|
+
enlarg_1 = np.linspace(Y [0] - nb_enlarg * dz, Y [0] - dy, nb_enlarg)
|
|
71
|
+
enlarg_2 = np.linspace(Y [- 1] + dy, Y [- 1] + nb_enlarg * dy, nb_enlarg)
|
|
72
|
+
Y = np.concatenate((enlarg_1, Y ))
|
|
73
|
+
Y = np.concatenate((Y , enlarg_2))
|
|
74
|
+
if (type(self.By)==np.ndarray) :
|
|
75
|
+
enlarg_3 = np.zeros(nb_enlarg)
|
|
76
|
+
self.By = np.concatenate((enlarg_3, self.By))
|
|
77
|
+
self.By = np.concatenate((self.By, enlarg_3))
|
|
78
|
+
return Z,Y
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def plot_z(self,X,Y,Z,title="Magnetic field",field_component=None):
|
|
84
|
+
import matplotlib.pyplot as plt
|
|
85
|
+
|
|
86
|
+
if ( (field_component == None) or (field_component == 0) or (field_component == 'x') ):
|
|
87
|
+
plt.plot(Z, self.Bx(z=Z,y=Y,x=X))
|
|
88
|
+
|
|
89
|
+
plt.ylabel('Bx [T]')
|
|
90
|
+
plt.xlabel('Z [m]')
|
|
91
|
+
plt.title(title+" Bx = f(z) ")
|
|
92
|
+
plt.show()
|
|
93
|
+
|
|
94
|
+
if ( (field_component == None) or (field_component == 1) or (field_component == 'y') ):
|
|
95
|
+
plt.plot(Z, self.By(z=Z,y=Y,x=X))
|
|
96
|
+
plt.ylabel('By [T]')
|
|
97
|
+
plt.xlabel('Z [m]')
|
|
98
|
+
plt.title(title+" By = f(z) ")
|
|
99
|
+
plt.show()
|
|
100
|
+
|
|
101
|
+
if ( (field_component == None) or (field_component == 2) or (field_component == 'z') ):
|
|
102
|
+
plt.plot(Z, self.Bz(z=Z,y=Y,x=X))
|
|
103
|
+
plt.ylabel('Bz [T]')
|
|
104
|
+
plt.xlabel('Z [m]')
|
|
105
|
+
plt.title(title+" Bz = f(z) ")
|
|
106
|
+
plt.show()
|
|
107
|
+
|
|
108
|
+
# # TODO A CHANGER COMME PLOT_z
|
|
109
|
+
#TODO quiver plot ?
|
|
110
|
+
# def plot_y(self):
|
|
111
|
+
# plt.plot(self.y, self.Bx(self.z, self.y))
|
|
112
|
+
# plt.title(" Bx = f(y) ")
|
|
113
|
+
# plt.xlabel('Bx')
|
|
114
|
+
# plt.ylabel('y')
|
|
115
|
+
# plt.show()
|
|
116
|
+
#
|
|
117
|
+
# plt.plot(self.y, self.By(self.z, self.y))
|
|
118
|
+
# plt.title(" By = f(y) ")
|
|
119
|
+
# plt.xlabel('By')
|
|
120
|
+
# plt.ylabel('y')
|
|
121
|
+
# plt.show()
|
|
122
|
+
#
|
|
123
|
+
# plt.plot(self.y, self.Bz(self.z, self.y))
|
|
124
|
+
# plt.title(" Bz = f(y) ")
|
|
125
|
+
# plt.xlabel('Bz')
|
|
126
|
+
# plt.ylabel('y')
|
|
127
|
+
# plt.show()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
if __name__ == "__main__" :
|
|
131
|
+
Bx = lambda x,y,z : np.cos(y*z)
|
|
132
|
+
By = lambda x,y,z : np.sin(x)*np.cos(z)
|
|
133
|
+
Bz = lambda x,y,z : np.sin(y*z)
|
|
134
|
+
|
|
135
|
+
B=MagneticField(Bx=Bx,By=By,Bz=Bz)
|
|
136
|
+
|
|
137
|
+
Z=np.linspace(0.0,2.*np.pi,10000)
|
|
138
|
+
Y=np.linspace(0.0,2.*np.pi,10000)
|
|
139
|
+
X=np.linspace(0.0,2.*np.pi,10000)
|
|
140
|
+
|
|
141
|
+
print('plot X=pi/2 , Y=1 , Z in [0,2 pi]')
|
|
142
|
+
B.plot_z(X=np.pi*0.5,Y=1.0,Z=Z)
|
|
143
|
+
print('plot X= pi/2 , Y and Z in [0,2 pi]')
|
|
144
|
+
B.plot_z(X=np.pi*0.5,Y=Y,Z=Z)
|
|
145
|
+
print('plot X , Y and Z in [0,2 pi]')
|
|
146
|
+
B.plot_z(X=X,Y=Y,Z=Z)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# /*##########################################################################
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2016 European Synchrotron Radiation Facility
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
# furnished to do so, subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
|
14
|
+
# all copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
# THE SOFTWARE.
|
|
23
|
+
#
|
|
24
|
+
# ###########################################################################*/
|
|
25
|
+
|
|
26
|
+
__authors__ = ["S Thery, M Glass, M Sanchez del Rio - ESRF ISDD Advanced Analysis and Modelling"]
|
|
27
|
+
__license__ = "MIT"
|
|
28
|
+
__date__ = "31/08/2016"
|
|
29
|
+
|
|
30
|
+
import numpy as np
|
|
31
|
+
import scipy.constants as codata
|
|
32
|
+
from abc import abstractmethod
|
|
33
|
+
from pySRU.MagneticField import MagneticField
|
|
34
|
+
|
|
35
|
+
PLANE_UNDULATOR=0
|
|
36
|
+
BENDING_MAGNET=1
|
|
37
|
+
|
|
38
|
+
class MagneticStructure(object):
|
|
39
|
+
def __init__(self, magnet_type ):
|
|
40
|
+
self.magnet_type=magnet_type
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def copy(self):
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def print_parameters(self):
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# magnetic field
|
|
53
|
+
@abstractmethod
|
|
54
|
+
def fct_magnetic_field(self, z, y, x, harmonic_number, coordonnee='y'):
|
|
55
|
+
return 0.0
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# TODO la faire plus jolie ?
|
|
59
|
+
def calculate_magnetic_field(self, Z, Y, X, harmonic_number=1, coordonnee='y'):
|
|
60
|
+
if (type(Z) == np.ndarray):
|
|
61
|
+
B = np.zeros_like(Z)
|
|
62
|
+
else:
|
|
63
|
+
if (type(Y) == np.ndarray):
|
|
64
|
+
B = np.zeros_like(Y)
|
|
65
|
+
else:
|
|
66
|
+
if (type(X) == np.ndarray):
|
|
67
|
+
B = np.zeros_like(X)
|
|
68
|
+
else:
|
|
69
|
+
B = self.fct_magnetic_field(z=Z, y=Y, x=X,
|
|
70
|
+
harmonic_number=harmonic_number, coordonnee=coordonnee)
|
|
71
|
+
|
|
72
|
+
if (type(Z) == np.ndarray):
|
|
73
|
+
if (type(Y) == np.ndarray):
|
|
74
|
+
if (len(Y) != len(Z)):
|
|
75
|
+
raise Exception(' Y and Z must have the same lenght')
|
|
76
|
+
if (type(X) == np.ndarray):
|
|
77
|
+
if (len(X) != len(Z)):
|
|
78
|
+
raise Exception(' X and Z must have the same lenght')
|
|
79
|
+
for i, Zi in enumerate(Z):
|
|
80
|
+
B[i] = self.fct_magnetic_field(z=Zi, y=Y[i], x=X[i],
|
|
81
|
+
harmonic_number=harmonic_number, coordonnee=coordonnee)
|
|
82
|
+
else:
|
|
83
|
+
for i, Zi in enumerate(Z):
|
|
84
|
+
B[i] = self.fct_magnetic_field(z=Zi, y=Y[i], x=X,
|
|
85
|
+
harmonic_number=harmonic_number, coordonnee=coordonnee)
|
|
86
|
+
else:
|
|
87
|
+
if (type(X) == np.ndarray):
|
|
88
|
+
if (len(X) != len(Z)):
|
|
89
|
+
raise Exception(' X and Z must have the same lenght')
|
|
90
|
+
for i, Zi in enumerate(Z):
|
|
91
|
+
B[i] = self.fct_magnetic_field(z=Zi, y=Y, x=X[i],
|
|
92
|
+
harmonic_number=harmonic_number, coordonnee=coordonnee)
|
|
93
|
+
else:
|
|
94
|
+
for i, Zi in enumerate(Z):
|
|
95
|
+
B[i] = self.fct_magnetic_field(z=Zi, y=Y, x=X,
|
|
96
|
+
harmonic_number=harmonic_number, coordonnee=coordonnee)
|
|
97
|
+
else:
|
|
98
|
+
if (type(Y) == np.ndarray):
|
|
99
|
+
if (type(X) == np.ndarray):
|
|
100
|
+
if (len(X) != len(Y)):
|
|
101
|
+
raise Exception(' X and Z must have the same lenght')
|
|
102
|
+
for i, Yi in enumerate(Y):
|
|
103
|
+
B[i] = self.fct_magnetic_field(z=Z, y=Yi, x=X[i], harmonic_number=harmonic_number,
|
|
104
|
+
coordonnee=coordonnee)
|
|
105
|
+
else:
|
|
106
|
+
if (type(X) == np.ndarray):
|
|
107
|
+
for i, Xi in enumerate(X):
|
|
108
|
+
B[i] = self.fct_magnetic_field(z=Z, y=Y, x=Xi, harmonic_number=harmonic_number,
|
|
109
|
+
coordonnee=coordonnee)
|
|
110
|
+
else:
|
|
111
|
+
B = self.fct_magnetic_field(z=Z, y=Y, x=X, harmonic_number=harmonic_number, coordonnee=coordonnee)
|
|
112
|
+
return B
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# a Magnetic structur create a magnetic field
|
|
116
|
+
# the object MagneticField is create like :
|
|
117
|
+
# Bx , By , Bz are function R**(3) -> R
|
|
118
|
+
# this function depend of the magnet type (BendingMagnet or undulator ..)
|
|
119
|
+
# X, Y can be array or number, they describe the area where we want to work
|
|
120
|
+
# Z must be an array , it will be use later
|
|
121
|
+
# they have not necessary the same len
|
|
122
|
+
# peux etre a changer et ne metrre que les fonctions ... oui
|
|
123
|
+
def create_magnetic_field(self, harmonic_number=1):
|
|
124
|
+
By = (lambda z, y, x: self.calculate_magnetic_field(Z=z, Y=y, X=x, harmonic_number=harmonic_number, coordonnee='y'))
|
|
125
|
+
Bz = (lambda z, y, x: self.calculate_magnetic_field(Z=z, Y=y, X=x, harmonic_number=harmonic_number, coordonnee='z'))
|
|
126
|
+
Bx = (lambda z, y, x: self.calculate_magnetic_field(Z=z, Y=y, X=x, harmonic_number=harmonic_number, coordonnee='x'))
|
|
127
|
+
B = MagneticField(Bx, By, Bz)
|
|
128
|
+
return B
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
if __name__ == "__main__" :
|
|
133
|
+
pass
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# /*##########################################################################
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2016 European Synchrotron Radiation Facility
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
# furnished to do so, subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
|
14
|
+
# all copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
# THE SOFTWARE.
|
|
23
|
+
#
|
|
24
|
+
# ###########################################################################*/
|
|
25
|
+
|
|
26
|
+
__authors__ = ["S Thery, M Glass, M Sanchez del Rio - ESRF ISDD Advanced Analysis and Modelling"]
|
|
27
|
+
__license__ = "MIT"
|
|
28
|
+
__date__ = "31/08/2016"
|
|
29
|
+
|
|
30
|
+
import numpy as np
|
|
31
|
+
import scipy.constants as codata
|
|
32
|
+
import scipy.special as special
|
|
33
|
+
from pySRU.MagneticStructure import MagneticStructure, PLANE_UNDULATOR,BENDING_MAGNET
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
#TODO changer et mettre la divergeance en parametre ?
|
|
37
|
+
class MagneticStructureBendingMagnet(MagneticStructure):
|
|
38
|
+
def __init__(self, Bo, horizontale_divergeance,electron_energy=1e9):
|
|
39
|
+
super(self.__class__, self).__init__(magnet_type=BENDING_MAGNET)
|
|
40
|
+
self.horizontal_div=horizontale_divergeance
|
|
41
|
+
self.radius_curv=electron_energy*1e9/(codata.c*Bo)
|
|
42
|
+
self.length=np.sin(horizontale_divergeance)*self.radius_curv
|
|
43
|
+
self.Bo = Bo
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def copy(self):
|
|
47
|
+
return MagneticStructureBendingMagnet(length=self.length, Bo=self.Bo)
|
|
48
|
+
|
|
49
|
+
def fct_magnetic_field(self, z, y, x, harmonic_number, coordonnee='y'):
|
|
50
|
+
Zo = self.length * 0.6
|
|
51
|
+
if coordonnee == 'y' and z >= -Zo and z <= Zo:
|
|
52
|
+
# codata.m_e * codata.c / codata.e= 0.00170450894933
|
|
53
|
+
Bo = self.Bo
|
|
54
|
+
|
|
55
|
+
else: # coordonnee == 'z' :
|
|
56
|
+
Bo = 0.0
|
|
57
|
+
return Bo
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def fct_magnetic_field2(self, z, y, x, harmonic_number, coordonnee='y'):
|
|
61
|
+
Zo = self.length * 0.5
|
|
62
|
+
if coordonnee == 'y':
|
|
63
|
+
# codata.m_e * codata.c / codata.e= 0.00170450894933
|
|
64
|
+
Bo = self.Bo
|
|
65
|
+
else: # coordonnee == 'z' :
|
|
66
|
+
Bo = 0.0
|
|
67
|
+
|
|
68
|
+
# we enelarge the real effect of the magnetic field by 4 lambda_u
|
|
69
|
+
# on each extremity of the undulator
|
|
70
|
+
L_magn_field = self.length * 1.5
|
|
71
|
+
|
|
72
|
+
# we know considere that if -(L/2 + lambda_u/4) < Z < (L/2 + lambda_u/4)
|
|
73
|
+
# the magnetic field if a classic cosinus (or sinus)
|
|
74
|
+
L_cosinus_part = -Zo
|
|
75
|
+
|
|
76
|
+
if ((z < -L_magn_field) or (z > L_magn_field)):
|
|
77
|
+
dB = 0.0
|
|
78
|
+
|
|
79
|
+
else:
|
|
80
|
+
if (z < -L_cosinus_part or z > L_cosinus_part):
|
|
81
|
+
|
|
82
|
+
# in this case, we work with a gaussian,
|
|
83
|
+
# so we shift the coordinate frame for use a central gaussian
|
|
84
|
+
if z > 0.0:
|
|
85
|
+
z_shift = z - L_cosinus_part
|
|
86
|
+
else:
|
|
87
|
+
z_shift = z + L_cosinus_part
|
|
88
|
+
|
|
89
|
+
sigma = (L_magn_field - L_cosinus_part) / 5.0
|
|
90
|
+
# dB= Bo*(1.0-z_shift*self.get_L()**2/2.0)*np.exp(-0.5*(z_shift/sigma)**2)
|
|
91
|
+
dB = Bo * np.exp(-0.5 * (z_shift / sigma) ** 2)
|
|
92
|
+
else:
|
|
93
|
+
# in this case we work in the cosinus part
|
|
94
|
+
dB = Bo
|
|
95
|
+
return dB
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def print_parameters(self):
|
|
100
|
+
print(" Magnetic Structure (Bending Magnet):")
|
|
101
|
+
print(' length : %.5f (m)'%self.length)
|
|
102
|
+
print(' magnetic_field_strength : %.5f'%self.Bo)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
if __name__ == "__main__" :
|
|
106
|
+
|
|
107
|
+
BM = MagneticStructureBendingMagnet(Bo=0.85, length=1e-3 * 20.0)
|
|
108
|
+
|
|
109
|
+
print('bending magnet test :')
|
|
110
|
+
BM.print_parameters()
|
|
111
|
+
B = BM.create_magnetic_field()
|
|
112
|
+
Z=np.linspace(-BM.length/2.0,BM.length/2.0,10000)
|
|
113
|
+
B.plot_z(Z=Z,Y=0.0,X=0.0)
|
|
114
|
+
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
# /*##########################################################################
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2016 European Synchrotron Radiation Facility
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
# furnished to do so, subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
|
14
|
+
# all copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
# THE SOFTWARE.
|
|
23
|
+
#
|
|
24
|
+
# ###########################################################################*/
|
|
25
|
+
|
|
26
|
+
__authors__ = ["S Thery, M Glass, M Sanchez del Rio - ESRF ISDD Advanced Analysis and Modelling"]
|
|
27
|
+
__license__ = "MIT"
|
|
28
|
+
__date__ = "31/08/2016"
|
|
29
|
+
|
|
30
|
+
import numpy as np
|
|
31
|
+
import scipy.constants as codata
|
|
32
|
+
from scipy.special import jn,yn,jv,yv
|
|
33
|
+
from pySRU.MagneticField import MagneticField
|
|
34
|
+
from pySRU.MagneticStructure import MagneticStructure , PLANE_UNDULATOR,BENDING_MAGNET
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class MagneticStructureUndulatorPlane(MagneticStructure):
|
|
39
|
+
def __init__(self, K, period_length, length):
|
|
40
|
+
super(self.__class__, self).__init__(magnet_type=PLANE_UNDULATOR)
|
|
41
|
+
self.K = K
|
|
42
|
+
self.period_length = period_length
|
|
43
|
+
self.length=length
|
|
44
|
+
|
|
45
|
+
def copy(self):
|
|
46
|
+
return MagneticStructureUndulatorPlane(K=self.K, period_length=self.period_length, length=self.length)
|
|
47
|
+
|
|
48
|
+
def fct_magnetic_field(self, z, y, x, harmonic_number, coordonnee='y'):
|
|
49
|
+
lambda_h = self.period_length / harmonic_number
|
|
50
|
+
ku = 2.0 * np.pi / self.period_length
|
|
51
|
+
|
|
52
|
+
if coordonnee == 'x':
|
|
53
|
+
dB = 0.0
|
|
54
|
+
else:
|
|
55
|
+
# codata.m_e * codata.c / codata.e= 0.00170450894933
|
|
56
|
+
K_to_B = ku * codata.m_e * codata.c / codata.e
|
|
57
|
+
if coordonnee == 'y':
|
|
58
|
+
|
|
59
|
+
Bo = (self.K * K_to_B) * np.cosh(ku * y)
|
|
60
|
+
# print(Bo)
|
|
61
|
+
f_base = np.cos
|
|
62
|
+
else: # coordonnee == 'z' :
|
|
63
|
+
Bo = -(self.K * K_to_B) * np.sinh(ku * y)
|
|
64
|
+
f_base = np.sin
|
|
65
|
+
|
|
66
|
+
# we enelarge the real effect of the magnetic field by 4 lambda_u
|
|
67
|
+
# on each extremity of the undulator
|
|
68
|
+
L_magn_field = self.length / 2.0 + 4.0 * self.period_length
|
|
69
|
+
|
|
70
|
+
# we know considere that if -(L/2 + lambda_u/4) < Z < (L/2 + lambda_u/4)
|
|
71
|
+
# the magnetic field if a classic cosinus (or sinus)
|
|
72
|
+
if coordonnee == 'y':
|
|
73
|
+
a1 = self.length / self.period_length \
|
|
74
|
+
- np.floor(self.period_number())
|
|
75
|
+
a2 = (0.25 - a1 / 2.0)
|
|
76
|
+
L_cosinus_part = self.length / 2.0 \
|
|
77
|
+
+ self.period_length * a2
|
|
78
|
+
|
|
79
|
+
else:
|
|
80
|
+
L_cosinus_part = self.length / 2.0
|
|
81
|
+
|
|
82
|
+
if ((z < -L_magn_field) or (z > L_magn_field)):
|
|
83
|
+
dB = 0.0
|
|
84
|
+
|
|
85
|
+
else:
|
|
86
|
+
if (z < -L_cosinus_part or z > L_cosinus_part):
|
|
87
|
+
|
|
88
|
+
# in this case, we work with a gaussian,
|
|
89
|
+
# so we shift the coordinate frame for use a central gaussian
|
|
90
|
+
if z < -L_cosinus_part:
|
|
91
|
+
sign = 1
|
|
92
|
+
else: # z> L_cosinus_part
|
|
93
|
+
sign = -1
|
|
94
|
+
|
|
95
|
+
shift_z = z + sign * L_cosinus_part
|
|
96
|
+
|
|
97
|
+
p = 2.0 * np.pi ** 2 / (3.0 * lambda_h ** 2)
|
|
98
|
+
dB = ((2.0 * np.pi * Bo / lambda_h) * shift_z) * (
|
|
99
|
+
1.0 - 4.0 * np.pi ** 2 * shift_z ** 2 / (9.0 * lambda_h ** 2)
|
|
100
|
+
) * np.exp(-p * shift_z ** 2)
|
|
101
|
+
|
|
102
|
+
# test du signe
|
|
103
|
+
z_test = sign * (-L_cosinus_part + lambda_h / 4.0)
|
|
104
|
+
test_trig = f_base(ku * z_test)
|
|
105
|
+
if (sign * test_trig < 0):
|
|
106
|
+
dB = -dB
|
|
107
|
+
|
|
108
|
+
else:
|
|
109
|
+
# in this case we work in the cosinus part
|
|
110
|
+
dB = Bo * f_base(ku * z)
|
|
111
|
+
|
|
112
|
+
return dB
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def print_parameters(self):
|
|
116
|
+
print(' Magnetic Structure (Plane Undulator)')
|
|
117
|
+
print(' K : %.2f'%(self.K))
|
|
118
|
+
print(' period lenght : %.3f' % (self.period_length))
|
|
119
|
+
print(' lenght : %.2f'% (self.length))
|
|
120
|
+
print(' number of periods : %d (L/lambdau=%.2f)' % (int(self.period_number()),self.period_number()))
|
|
121
|
+
print(' magntic field intensity: %.2f'% (self.magnetic_field_strength()))
|
|
122
|
+
|
|
123
|
+
def period_number(self):
|
|
124
|
+
return self.length / self.period_length
|
|
125
|
+
|
|
126
|
+
def magnetic_field_strength(self):
|
|
127
|
+
Bo = (2.0 * np.pi * codata.m_e * codata.c * self.K) / (
|
|
128
|
+
self.period_length * codata.e)
|
|
129
|
+
return Bo
|
|
130
|
+
|
|
131
|
+
if __name__ == "__main__" :
|
|
132
|
+
und_test = MagneticStructureUndulatorPlane(K=1.87, period_length=0.035, length=0.035 * 14)
|
|
133
|
+
ESRF18 = MagneticStructureUndulatorPlane(K=1.68, period_length=0.018, length=2.0)
|
|
134
|
+
|
|
135
|
+
print('undulator test :')
|
|
136
|
+
und_test.print_parameters()
|
|
137
|
+
B=und_test.create_magnetic_field()
|
|
138
|
+
Z=np.linspace(-und_test.length/2.0,und_test.length/2.0,10000)
|
|
139
|
+
B.plot_z(Z=Z,Y=0.0,X=0.0)
|
|
140
|
+
|
|
141
|
+
print('undulator ESRF18 :')
|
|
142
|
+
ESRF18.print_parameters()
|
|
143
|
+
B=ESRF18.create_magnetic_field()
|
|
144
|
+
Z=np.linspace(-ESRF18.length/2.0,ESRF18.length/2.0,10000)
|
|
145
|
+
B.plot_z(Z=Z,Y=0.0,X=0.0)
|