"""
The s4 refractive lens (optical element and beamline element).
"""
import numpy
from syned.beamline.element_coordinates import ElementCoordinates
from syned.beamline.optical_elements.refractors.lens import Lens
from syned.beamline.shape import Rectangle, Ellipse, Circle
from dabax.dabax_xraylib import DabaxXraylib
from shadow4.beam.s4_beam import S4Beam
from shadow4.beamline.s4_beamline_element import S4BeamlineElement
from shadow4.beamline.s4_beamline_element_movements import S4BeamlineElementMovements
from shadow4.beamline.optical_elements.refractors.s4_conic_interface import S4ConicInterface, S4ConicInterfaceElement
from shadow4.beamline.s4_optical_element_decorators import S4RefractiveLensOpticalElementDecorator
[docs]class S4Lens(Lens, S4RefractiveLensOpticalElementDecorator):
"""
Constructor.
Parameters
----------
name : str, optional
The name of the mirror.
boundary_shape : instance of BoundaryShape, optional
The boundary shape of the mirror.
material : str, optional
A string with the material element symbol or compound formula.
density : float, optional
The density of the material in the lens in g/cm^3.
thickness : float, optional
The thickness of a single lens in m.
surface_shape : int, optional
A flag to indicate the shape of the optical surfaces: 0=plane, 1=sphere, 2=parabola, 3=conic coefficients.
convex_to_the_beam : int, optional
A flag to indicate the convexity of the first optical surface. Used for surface_shape > 0.
The first interface exposed to the beam is convex: 0=No, 1=Yes.
The second interface has opposite convexity.
cylinder_angle : int, optional
A flag to indicate is the CRL is 2D0fucusing, aor 1D focusing and in which direction:
Used for surface_shape > 0. Values are:
0=CRL is focusing in 2D (not cylindrical),
1=CRL is focusing in 1D (meridional focusing),
2=CRL is focusing in 2D (sagittal focusing).
ri_calculation_mode : int, optional
A flag to indicate the source of the refraction index. Values are:
* 0=User,
* 1=prerefl file,
* 2=direct calculation using xraylib,
* 3=direct calculation using dabax.
prerefl_file : str, optional
For ri_calculation_mode=1, the prerefl preprocessor file name.
refraction_index : float, optional
For ri_calculation_mode=0, the real part of the refraction index.
attenuation_coefficient : float, optional
For ri_calculation_mode=0, the attenuation coefficient in m^-1 !!!.
dabax : None or instance of DabaxXraylib,
The pointer to the dabax library (used for ri_calculation_mode=3). If None, the default is used.
radius : float, optional
For surface_shape=(1,2), the lens radius in m. (For parabolic lenses, it is the radius at the tip for paraboloid.)
conic_coefficients1 : None or list, optional
For surface_shape=3, A list with the 10 conic coefficients of interface 1. None is considered as Plane.
conic_coefficients2 : None or list, optional
For surface_shape=3, A list with the 10 conic coefficients of interface 2. None is considered as Plane.
"""
def __init__(self,
name="Undefined",
boundary_shape=None, # syned stuff, replaces "diameter" in the shadow3 append_lens
material="", # syned stuff, not (yet) used
thickness=0.0, # syned stuff, lens thickness [m] (distance between the two interfaces at the center of the lenses)
surface_shape=1, # now: 0=plane, 1=sphere, 2=parabola, 3=conic coefficients
# (in shadow3: 1=sphere 4=paraboloid, 5=plane)
convex_to_the_beam=1, # for surface_shape (1,2): convexity of the first interface exposed to the beam 0=No, 1=Yes
# the second interface has opposite convexity
cylinder_angle=0, # for surface_shape (1,2): 0=not cylindricaL, 1=meridional 2=sagittal
ri_calculation_mode=0, # source of refraction indices and absorption coefficients
# 0=User
# 1=prerefl file
# 2=direct calculation using xraylib
# 3=direct calculation using dabax
prerefl_file=None, # for ri_calculation_mode=0: file name (from prerefl) to get the refraction index.
refraction_index=1.0, # for ri_calculation_mode=1: n (real)
attenuation_coefficient=0.0, # for ri_calculation_mode=1: mu in m^-1 (real)
density=1.0,
dabax=None, # for ri_calculation_mode=3
radius=500e-6, # for surface_shape=(1,2): lens radius [m] (for spherical, or radius at the tip for paraboloid)
conic_coefficients1=None, # for surface_shape = 3: the conic coefficients of the first interface
conic_coefficients2=None, # for surface_shape = 3: the conic coefficients of the second interface
):
S4RefractiveLensOpticalElementDecorator.__init__(self,
surface_shape,
convex_to_the_beam,
cylinder_angle,
ri_calculation_mode,
prerefl_file,
refraction_index,
attenuation_coefficient,
density,
dabax,
radius,
conic_coefficients1,
conic_coefficients2)
Lens.__init__(self,
name=name,
surface_shape1=self.get_surface_shape_instance()[0],
surface_shape2=self.get_surface_shape_instance()[1],
boundary_shape=boundary_shape,
material=material,
thickness=thickness)
if ri_calculation_mode == 3:
if isinstance(dabax, DabaxXraylib):
dabax_txt = 'DabaxXraylib(file_f1f2="%s", file_CrossSec="%s")' % \
(dabax.get_file_f1f2(), dabax.get_file_CrossSec())
else:
dabax_txt = 'DabaxXraylib()'
else:
dabax_txt = "None"
self.__inputs = {
"name": name,
"boundary_shape": boundary_shape,
"material": material,
"thickness": thickness,
"surface_shape": surface_shape,
"convex_to_the_beam": convex_to_the_beam,
"cylinder_angle": cylinder_angle,
"ri_calculation_mode": ri_calculation_mode,
"prerefl_file": prerefl_file,
"refraction_index": refraction_index,
"attenuation_coefficient": attenuation_coefficient,
"density": density,
"dabax": dabax_txt,
"radius": radius,
"conic_coefficients1": repr(conic_coefficients1),
"conic_coefficients2": repr(conic_coefficients2),
}
[docs] def interthickness(self):
"""
Returns the interthickness of the beamline element, which is the distance covered by the element along the
optical axis.
Elements with a single optical surface (mirrors, crystals, etc.) have interthickness zero.
Elements like lenses, CRL, transfocators, etc. have interthickness > 0. It is redefined in this method.
Note that the interthickness is the projection along the (image) optical axis.
Returns
-------
float
"""
return self.get_thickness()
[docs] def to_python_code_boundary_shape(self):
"""
Creates a code block with information of boundary shape.
Returns
-------
str
The text with the code.
"""
txt = ""
bs = self._boundary_shape
if bs is None:
txt += "\nboundary_shape = None"
elif isinstance(bs, Rectangle):
txt += "\nfrom syned.beamline.shape import Rectangle"
txt += "\nboundary_shape = Rectangle(x_left=%g, x_right=%g, y_bottom=%g, y_top=%g)" % bs.get_boundaries()
elif isinstance(bs, Circle):
txt += "\nfrom syned.beamline.shape import Circle"
txt += "\nboundary_shape = Circle(radius=%g, x_center=%g,y_center=%g)" % bs.get_boundaries()
elif isinstance(bs, Ellipse):
txt += "\nfrom syned.beamline.shape import Ellipse"
txt += "\nboundary_shape = Ellipse(a_axis_min=%g, a_axis_max=%g, b_axis_min=%g, b_axis_max=%g)" % bs.get_boundaries()
return txt
[docs] def to_python_code(self, **kwargs):
"""
Creates the python code for defining the element.
Parameters
----------
**kwargs
Returns
-------
str
Python code.
"""
txt = self.to_python_code_boundary_shape()
txt_pre = """
from shadow4.beamline.optical_elements.refractors.s4_lens import S4Lens
optical_element = S4Lens(name='{name:s}',
boundary_shape=boundary_shape, # syned stuff, replaces "diameter" in the shadow3 append_lens
material='{material:s}', # the material for ri_calculation_mode > 1
density={density:g}, # the density for ri_calculation_mode > 1
thickness={thickness}, # syned stuff, lens thickness [m] (distance between the two interfaces at the center of the lenses)
surface_shape={surface_shape}, # 0=plane, 1=sphere, 2=parabola, 3=conic coefficients
convex_to_the_beam={convex_to_the_beam}, # for surface_shape: convexity of the first interface exposed to the beam 0=No, 1=Yes
cylinder_angle={cylinder_angle}, # for surface_shape: 0=not cylindricaL, 1=meridional 2=sagittal
ri_calculation_mode={ri_calculation_mode}, # source of refr indices and absorp coeff 0=User, 1=prerefl file, 2=xraylib, 3=dabax
prerefl_file='{prerefl_file:s}', # for ri_calculation_mode=0: file name (from prerefl) to get the refraction index.
refraction_index={refraction_index:.10g}, # for ri_calculation_mode=1: n (real)
attenuation_coefficient={attenuation_coefficient:g}, # for ri_calculation_mode=1: mu in m^-1 (real)
dabax={dabax:s}, # if using dabax (ri_calculation_mode=3), instance of DabaxXraylib() (use None for default)
radius={radius:g}, # for surface_shape=(1,2): lens radius [m] (for spherical, or radius at the tip for paraboloid)
conic_coefficients1={conic_coefficients1}, # for surface_shape = 3: the conic coefficients for interface 1
conic_coefficients2={conic_coefficients2}, # for surface_shape = 3: the conic coefficients for interface 2
)
"""
txt += txt_pre.format(**self.__inputs)
return txt
[docs] def get_lens_interfaces(self):
return _get_lens_interfaces(lens_optical_surfaces=self.get_optical_surface_instance(),
boundary_shape=self.get_boundary_shape(),
ri_calculation_mode=self._ri_calculation_mode,
refraction_index=self._refraction_index,
attenuation_coefficient=self._attenuation_coefficient,
prerefl_file=self._prerefl_file,
material=self.get_material(),
density=self._density,
dabax=self._dabax,
)
def _get_lens_interfaces(lens_optical_surfaces,
boundary_shape,
ri_calculation_mode,
refraction_index,
attenuation_coefficient,
prerefl_file,
material,
density,
dabax):
conic_coefficients1 = lens_optical_surfaces[0].get_coefficients()
conic_coefficients2 = lens_optical_surfaces[1].get_coefficients()
if ri_calculation_mode == 0: # user
half_lens_1 = S4ConicInterface(
name="First half-lens",
boundary_shape=boundary_shape,
material_object=None,
material_image=None,
f_r_ind=0, # source of optical constants, from constant value or PREREFL preprocessor (file):
# (0) constant value in both object and image spaces
# (1) file in object space, constant value in image space
# (2) constant value in object space, file in image space
# (3) file in both object and image space
r_ind_obj=1.0, # (for f_r_ind=0,2): index of refraction in object space.
r_ind_ima=refraction_index, # (for f_r_ind=0,1): index of refraction in image space.
r_attenuation_obj=0.0, # (for f_r_ind=0,2): attenuation coefficient in object space. Units of UserUnitLength^(-1)
r_attenuation_ima=attenuation_coefficient, # (for f_r_ind=0,1): attenuation coefficient in image space. Units of m-1
file_r_ind_obj="", # (for f_r_ind=1,3): file generated by PREREFL
file_r_ind_ima="", # (for f_r_ind=2,3): file generated by PREREFL
conic_coefficients=conic_coefficients1,
)
half_lens_2 = S4ConicInterface(
name="Second half-lens",
boundary_shape=boundary_shape,
material_object=None,
material_image=None,
f_r_ind=0, # source of optical constants, from constant value or PREREFL preprocessor (file):
# (0) constant value in both object and image spaces
# (1) file in object space, constant value in image space
# (2) constant value in object space, file in image space
# (3) file in both object and image space
r_ind_obj=refraction_index, # (for f_r_ind=0,2): index of refraction in object space.
r_ind_ima=1.0, # (for f_r_ind=0,1): index of refraction in image space.
r_attenuation_obj=attenuation_coefficient, # (for f_r_ind=0,2): attenuation coefficient in object space. Units of m^-1
r_attenuation_ima=0.0, # (for f_r_ind=0,1): attenuation coefficient in image space. Units of UserUnitLength^(-1)
file_r_ind_obj="", # (for f_r_ind=1,3): file generated by PREREFL
file_r_ind_ima="", # (for f_r_ind=2,3): file generated by PREREFL
conic_coefficients=conic_coefficients2,
)
elif ri_calculation_mode == 1: # prerefl file
half_lens_1 = S4ConicInterface(
name="First half-lens",
boundary_shape=boundary_shape,
material_object=None,
material_image=None,
f_r_ind=2, # source of optical constants, from constant value or PREREFL preprocessor (file):
# (0) constant value in both object and image spaces
# (1) file in object space, constant value in image space
# (2) constant value in object space, file in image space
# (3) file in both object and image space
r_ind_obj=1.0, # (for f_r_ind=0,2): index of refraction in object space.
r_ind_ima=1.0, # (for f_r_ind=0,1): index of refraction in image space.
r_attenuation_obj=0.0, # (for f_r_ind=0,2): attenuation coefficient in object space. Units of UserUnitLength^(-1)
r_attenuation_ima=0.0, # (for f_r_ind=0,1): attenuation coefficient in image space. Units of UserUnitLength^(-1)
file_r_ind_obj="", # (for f_r_ind=1,3): file generated by PREREFL
file_r_ind_ima=prerefl_file, # (for f_r_ind=2,3): file generated by PREREFL
conic_coefficients=conic_coefficients1,
)
half_lens_2 = S4ConicInterface(
name="Second half-lens",
boundary_shape=boundary_shape,
material_object=None,
material_image=None,
f_r_ind=1, # source of optical constants, from constant value or PREREFL preprocessor (file):
# (0) constant value in both object and image spaces
# (1) file in object space, constant value in image space
# (2) constant value in object space, file in image space
# (3) file in both object and image space
r_ind_obj=1.0, # (for f_r_ind=0,2): index of refraction in object space.
r_ind_ima=1.0, # (for f_r_ind=0,1): index of refraction in image space.
r_attenuation_obj=0.0, # (for f_r_ind=0,2): attenuation coefficient in object space. Units of UserUnitLength^(-1)
r_attenuation_ima=0.0, # (for f_r_ind=0,1): attenuation coefficient in image space. Units of UserUnitLength^(-1)
file_r_ind_obj=prerefl_file, # (for f_r_ind=1,3): file generated by PREREFL
file_r_ind_ima="", # (for f_r_ind=2,3): file generated by PREREFL
conic_coefficients=conic_coefficients2,
)
elif ri_calculation_mode == 2: # xraylib
half_lens_1 = S4ConicInterface(
name="First half-lens",
boundary_shape=boundary_shape,
material_object=None,
material_image=material,
density_object=1.0,
density_image=density,
f_r_ind=5, # source of optical constants, from constant value or PREREFL preprocessor (file):
# (0) constant value in both object and image spaces
# (1) file in object space, constant value in image space
# (2) constant value in object space, file in image space
# (3) file in both object and image space
r_ind_obj=1.0, # (for f_r_ind=0,2): index of refraction in object space.
r_ind_ima=1.0, # (for f_r_ind=0,1): index of refraction in image space.
r_attenuation_obj=0.0, # (for f_r_ind=0,2): attenuation coefficient in object space. Units of UserUnitLength^(-1)
r_attenuation_ima=0.0, # (for f_r_ind=0,1): attenuation coefficient in image space. Units of UserUnitLength^(-1)
file_r_ind_obj="", # (for f_r_ind=1,3): file generated by PREREFL
file_r_ind_ima=prerefl_file, # (for f_r_ind=2,3): file generated by PREREFL
conic_coefficients=conic_coefficients1,
)
half_lens_2 = S4ConicInterface(
name="Second half-lens",
boundary_shape=boundary_shape,
material_object=material,
material_image=None,
density_object=density,
density_image=1.0,
f_r_ind=4, # source of optical constants, from constant value or PREREFL preprocessor (file):
# (0) constant value in both object and image spaces
# (1) file in object space, constant value in image space
# (2) constant value in object space, file in image space
# (3) file in both object and image space
r_ind_obj=1.0, # (for f_r_ind=0,2): index of refraction in object space.
r_ind_ima=1.0, # (for f_r_ind=0,1): index of refraction in image space.
r_attenuation_obj=0.0, # (for f_r_ind=0,2): attenuation coefficient in object space. Units of UserUnitLength^(-1)
r_attenuation_ima=0.0, # (for f_r_ind=0,1): attenuation coefficient in image space. Units of UserUnitLength^(-1)
file_r_ind_obj=prerefl_file, # (for f_r_ind=1,3): file generated by PREREFL
file_r_ind_ima="", # (for f_r_ind=2,3): file generated by PREREFL
conic_coefficients=conic_coefficients2,
)
elif ri_calculation_mode == 3: # dabax
half_lens_1 = S4ConicInterface(
name="First half-lens",
boundary_shape=boundary_shape,
material_object=None,
material_image=material,
density_object=1.0,
density_image=density,
f_r_ind=8, # source of optical constants, from constant value or PREREFL preprocessor (file):
# (0) constant value in both object and image spaces
# (1) file in object space, constant value in image space
# (2) constant value in object space, file in image space
# (3) file in both object and image space
r_ind_obj=1.0, # (for f_r_ind=0,2): index of refraction in object space.
r_ind_ima=1.0, # (for f_r_ind=0,1): index of refraction in image space.
r_attenuation_obj=0.0, # (for f_r_ind=0,2): attenuation coefficient in object space. Units of UserUnitLength^(-1)
r_attenuation_ima=0.0, # (for f_r_ind=0,1): attenuation coefficient in image space. Units of UserUnitLength^(-1)
file_r_ind_obj="", # (for f_r_ind=1,3): file generated by PREREFL
file_r_ind_ima=prerefl_file, # (for f_r_ind=2,3): file generated by PREREFL
dabax=dabax,
conic_coefficients=conic_coefficients1,
)
half_lens_2 = S4ConicInterface(
name="Second half-lens",
boundary_shape=boundary_shape,
material_object=material,
material_image=None,
density_object=density,
density_image=1.0,
f_r_ind=7, # source of optical constants, from constant value or PREREFL preprocessor (file):
# (0) constant value in both object and image spaces
# (1) file in object space, constant value in image space
# (2) constant value in object space, file in image space
# (3) file in both object and image space
r_ind_obj=1.0, # (for f_r_ind=0,2): index of refraction in object space.
r_ind_ima=1.0, # (for f_r_ind=0,1): index of refraction in image space.
r_attenuation_obj=0.0, # (for f_r_ind=0,2): attenuation coefficient in object space. Units of UserUnitLength^(-1)
r_attenuation_ima=0.0, # (for f_r_ind=0,1): attenuation coefficient in image space. Units of UserUnitLength^(-1)
file_r_ind_obj=prerefl_file, # (for f_r_ind=1,3): file generated by PREREFL
file_r_ind_ima="", # (for f_r_ind=2,3): file generated by PREREFL
dabax=dabax,
conic_coefficients=conic_coefficients2,
)
return half_lens_1, half_lens_2
[docs]class S4LensElement(S4BeamlineElement):
"""
Constructor.
Parameters
----------
optical_element : instance of OpticalElement, optional
The syned optical element.
coordinates : instance of ElementCoordinates, optional
The syned element coordinates.
movements : instance of S4BeamlineElementMovements, optional
The S4 element movements. (The same movements are applied to the two interfaces. Therefore, each rotation is
applied around the local axes of each interface, which are different.)
input_beam : instance of S4Beam, optional
The S4 incident beam.
Returns
-------
instance of S4LensElement.
"""
def __init__(self,
optical_element : S4Lens = None,
coordinates : ElementCoordinates = None,
movements: S4BeamlineElementMovements = None,
input_beam : S4Beam = None):
super().__init__(optical_element=optical_element if optical_element is not None else S4Lens(),
coordinates=coordinates if coordinates is not None else ElementCoordinates(),
movements=movements,
input_beam=input_beam)
[docs] def to_python_code(self, **kwargs):
"""
Creates the python code for defining the element.
Parameters
----------
**kwargs
Returns
-------
str
Python code.
"""
txt = "\n\n# optical element number XX"
txt += self.get_optical_element().to_python_code()
txt += "\nimport numpy"
txt += self.to_python_code_coordinates()
txt += self.to_python_code_movements()
txt += "\nfrom shadow4.beamline.optical_elements.refractors.s4_lens import S4LensElement"
txt += "\nbeamline_element = S4LensElement(optical_element=optical_element, coordinates=coordinates, movements=movements, input_beam=beam)"
txt += "\n\nbeam, footprint = beamline_element.trace_beam()"
return txt
# def trace_beam(self, **params):
# # raise NotImplementedError()
[docs] def trace_beam(self, **params):
"""
Runs (ray tracing) the input beam through the element.
Parameters
----------
**params
Returns
-------
tuple
(output_beam, footprint) instances of S4Beam.
"""
# p = self.get_coordinates().p()
# q = self.get_coordinates().q()
# theta_grazing1 = numpy.pi / 2 - self.get_coordinates().angle_radial()
# theta_grazing2 = numpy.pi / 2 - self.get_coordinates().angle_radial_out()
# alpha1 = self.get_coordinates().angle_azimuthal()
#
# #
input_beam = self.get_input_beam().duplicate()
movements = self.get_movements()
oe = self.get_optical_element()
half_lens_1, half_lens_2 = oe.get_lens_interfaces()
#print(half_lens_1.inputs)
p, q, angle_radial, angle_radial_out, angle_azimuthal = self.get_coordinates().get_positions()
coordinates_1 = ElementCoordinates(p=p, q=oe.get_thickness() * 0.5, angle_radial=angle_radial, angle_radial_out=numpy.pi, angle_azimuthal=angle_azimuthal)
coordinates_2 = ElementCoordinates(p=oe.get_thickness() * 0.5, q=q, angle_radial=0, angle_radial_out=angle_radial_out, angle_azimuthal=0)
beamline_element_1 = S4ConicInterfaceElement(optical_element=half_lens_1, coordinates=coordinates_1, movements=movements, input_beam=input_beam)
beam1, footprint1 = beamline_element_1.trace_beam()
# return beam1, footprint1
beamline_element_2 = S4ConicInterfaceElement(optical_element=half_lens_2, coordinates=coordinates_2, movements=movements, input_beam=beam1)
beam2, footprint2 = beamline_element_2.trace_beam()
return beam2, [footprint1, footprint2]
if __name__ == "__main__":
import numpy
#
# collimated source
#
from shadow4.sources.source_geometrical.source_geometrical import SourceGeometrical
src = SourceGeometrical(nrays=10000)
src.set_energy_distribution_singleline(value=15000, unit='eV')
src.set_spatial_type_rectangle(width=1e-3, height=1e-3)
src.set_angular_distribution_uniform(0, 0, 0, 0)
beam = src.get_beam()
#
# lens (Be)
#
lens = S4Lens(name="Undefined",
boundary_shape=None, # syned stuff, replaces "diameter" in the shadow3 append_lens
material="", # syned stuff, not (yet) used
thickness=0.03, # syned stuff, lens thickness [m] (distance between the two interfaces at the center of the lenses)
surface_shape=2, # now: 0=plane, 1=sphere, 2=parabola, 3=conic coefficients
# (in shadow3: 1=sphere 4=paraboloid, 5=plane)
convex_to_the_beam=0, # for surface_shape (1,2): convexity of the first interface exposed to the beam 0=No, 1=Yes
# the second interface has opposite convexity
cylinder_angle=0, # for surface_shape (1,2): 0=not cylindricaL, 1=meridional 2=sagittal
ri_calculation_mode=3, # source of refraction indices and absorption coefficients
# 0=User
# 1=prerefl file
# 2=direct calculation using xraylib
# 3=direct calculation using dabax
prerefl_file="/users/srio/Oasys/reflec.dat", # for ri_calculation_mode=0: file name (from prerefl) to get the refraction index.
refraction_index=1.5, # for ri_calculation_mode=1: n (real)
attenuation_coefficient=1e-3, # for ri_calculation_mode=1: mu in m^-1 (real)
radius=0.1, # for surface_shape=(1,2): lens radius [m] (for spherical, or radius at the tip for paraboloid)
conic_coefficients1=None, # for surface_shape = 3: the conic coefficients of interface 1
conic_coefficients2=None, # for surface_shape = 3: the conic coefficients of interface 2
)
e = S4LensElement(optical_element=lens,
coordinates=ElementCoordinates(p=10, q=20,
angle_radial=0, angle_azimuthal=0, angle_radial_out=numpy.pi),
input_beam=beam)
print(e.to_python_code())
beam, footprints = e.trace_beam()
print("Intensity: ", beam.intensity(nolost=1))
# test plot
if True:
from srxraylib.plot.gol import plot_scatter
# plot_scatter(beam.get_photon_energy_eV(nolost=1), beam.get_column(23, nolost=1),
# title='(Intensity,Photon Energy)', plot_histograms=0)
plot_scatter(1e6 * beam.get_column(1, nolost=1), 1e6 * beam.get_column(3, nolost=1), title="(X,Z) in microns")
plot_scatter(1e6 * beam.get_column(4, nolost=1), 1e6 * beam.get_column(6, nolost=1), title="(X',Z') in microns")
print(lens.info())
print(e.to_python_code())