"""
Defines the functionality for shadow4 optical elements.
Map:
S4OpticalElementDecorator-----
|
|-----S4PlaneOpticalElementDecorator
|-----S4CurvedOpticalElementDecorator---
|----- S4SphereOpticalElementDecorator
|----- S4EllipsoidOpticalElementDecorator
|----- S4HyperboloidOpticalElementDecorator
|----- S4ToroidOpticalElementDecorator
|----- S4ParaboloidOpticalElementDecorator
|----- S4ConicOpticalElementDecorator
|----- S4NumericalMeshOpticalElementDecorator
|----- S4RefractiveLensOpticalElementDecorator
Basically it adds some methods:
- get_info: to be overloaded with specific info for a particular optical element.
- to_python_code: to be overloaded to create the python code for the specifoc optical element.
- get_surface_shape_instance: returns the SYNED shape instance.
- get_optical_surface_instance: returns the S4 optical surface instance.
"""
import numpy
import os
from syned.beamline.shape import Direction, Convexity
from syned.beamline.shape import Sphere, SphericalCylinder
from syned.beamline.shape import Ellipsoid, EllipticalCylinder
from syned.beamline.shape import Hyperboloid, HyperbolicCylinder
from syned.beamline.shape import Paraboloid, ParabolicCylinder
from syned.beamline.shape import Toroid, Conic, NumericalMesh, Plane, Side
from shadow4.optical_surfaces.s4_conic import S4Conic
from shadow4.optical_surfaces.s4_mesh import S4Mesh
from shadow4.optical_surfaces.s4_toroid import S4Toroid
from shadow4.tools.logger import is_verbose, is_debug
[docs]class S4OpticalElementDecorator(object):
"""
Base abstract class.
"""
def __init__(self):
pass
[docs] def get_info(self):
"""
Returns string containing some specific information of the shadow4 optical element.
Returns
-------
str
"""
return "\n\nSpecific information not available (get_info() method not overloaded in %s).\n\n" % self.__class__.__name__
[docs] def to_python_code(self, **kwargs):
"""
Returns string containing python code to create shadow4 optical element.
Raises
------
NotImplementedError.
"""
raise NotImplementedError()
[docs] def get_surface_shape_instance(self): # return a SYNED object of type Shape
"""
Returns a SYNED object of type Shape.
Raises
------
NotImplementedError.
"""
raise NotImplementedError()
[docs] def get_optical_surface_instance(self): # return a Shadow4 object of type S4OpticalSurface
"""
Returns a object of type S4OpticalSurface.
Raises
------
NotImplementedError.
"""
raise NotImplementedError()
[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.
This is the value returned here.
Elements like lenses, CRL, transfocators, etc. have interthickness > 0. They have to redefine this method.
Note that the interthickness is the projection along the (image) optical axis.
Returns
-------
float
"""
return 0.0
[docs]class SurfaceCalculation:
"""
class supporting the flag for external or internal calculation:
- INTERNAL = 0
- EXTERNAL = 1
"""
INTERNAL = 0
EXTERNAL = 1
[docs]class S4PlaneOpticalElementDecorator(S4OpticalElementDecorator):
"""
Creates the shadow4 optical element decorator for a plane surface.
"""
def __init__(self):
S4OpticalElementDecorator.__init__(self)
[docs] def get_surface_shape_instance(self):
"""
Returns the SYNED instance of type Shape.
Returns
-------
instance of syned.beamline.shape.Plane
"""
return Plane()
[docs] def get_optical_surface_instance(self):
"""
Returns a shadow4 optical element object of type optical surface.
Returns
-------
instance of shadow4.s4_optical_surfaces.s4_conic.S4Conic
"""
out = S4Conic.initialize_as_plane()
if is_verbose(): print("Plane ccc", out.ccc)
return out
[docs]class S4CurvedOpticalElementDecorator(S4OpticalElementDecorator):
"""
Creates the shadow4 optical element decorator for a curved surface.
Parameters
----------
surface_calculation : int, optional
flag:
- 0 = SurfaceCalculation.INTERNAL,
- 1 = SurfaceCalculation.EXTERNAL.
is_cylinder : int, optional
flag:
- 0=No (there is revolution symmetry along Y)
- 1=Yes (flat surface along X or Y).
curved_surface_shape : syned shape instance, optional
"""
def __init__(self,
surface_calculation=SurfaceCalculation.INTERNAL,
is_cylinder=False,
curved_surface_shape=None
):
S4OpticalElementDecorator.__init__(self)
self._surface_calculation = surface_calculation
self._is_cylinder = is_cylinder
self._curved_surface_shape = curved_surface_shape
[docs] def get_surface_shape_instance(self):
"""
Returns the SYNED instance of type Shape.
Returns
-------
instance of shape class.
"""
return self._curved_surface_shape
##################################################
# CURVED OPTICAL ELEMENTS
##################################################
[docs]class S4SphereOpticalElementDecorator(S4CurvedOpticalElementDecorator):
def __init__(self,
surface_calculation=SurfaceCalculation.INTERNAL, # external=1, internal=0
is_cylinder=False,
cylinder_direction=Direction.TANGENTIAL,
convexity=Convexity.UPWARD,
radius=0.0,
p_focus=0.0,
q_focus=0.0,
grazing_angle=0.0,
):
"""
Creates the shadow4 optical element decorator for a Sphere surface.
Parameters
----------
surface_calculation : int, optional
flag:
0 = SurfaceCalculation.INTERNAL,
1 = SurfaceCalculation.EXTERNAL.
is_cylinder : int, optional
flag:
0=No (there is revolution symmetry along Y)
1=Yes (flat surface along X or Y).
cylinder_direction : int (as defined by Direction), optional
TANGENTIAL = 0, SAGITTAL = 1.
convexity : int (as defined by Convexity), optional
NONE = -1, UPWARD = 0, DOWNWARD = 1.
radius : float, optional
The radius of the sphere.
p_focus : float, optional
For surface_calculation=1, the p distance (from source plane to center of the optical element).
q_focus : float, optional
For surface_calculation=1, the q distance (from the center of the optical element to the image plane).
grazing_angle : float, optional
For surface_calculation=1, the grazing angle in rad.
"""
if surface_calculation == SurfaceCalculation.EXTERNAL:
if is_cylinder: curved_surface_shape = SphericalCylinder.create_spherical_cylinder_from_radius(radius, convexity, cylinder_direction)
else: curved_surface_shape = Sphere.create_sphere_from_radius(radius, convexity)
else:
if is_cylinder: curved_surface_shape = SphericalCylinder.create_spherical_cylinder_from_p_q(p_focus, q_focus, grazing_angle, convexity, cylinder_direction)
else: curved_surface_shape = Sphere.create_sphere_from_p_q(p_focus, q_focus, grazing_angle, convexity)
S4CurvedOpticalElementDecorator.__init__(self,
surface_calculation=surface_calculation,
is_cylinder=is_cylinder,
curved_surface_shape=curved_surface_shape)
[docs] def get_optical_surface_instance(self):
"""
Returns a shadow4 optical element object of type optical surface.
Returns
-------
instance of shadow4.s4_optical_surfaces.s4_conic.S4Conic
"""
surface_shape = self.get_surface_shape_instance()
radius = surface_shape.get_radius()
switch_convexity = 0 if surface_shape.get_convexity() == Convexity.DOWNWARD else 1
if isinstance(surface_shape, SphericalCylinder):
cylindrical = 1
cylangle = 0.0 if surface_shape.get_cylinder_direction() == Direction.TANGENTIAL else (0.5 * numpy.pi)
elif isinstance(surface_shape, Sphere):
cylindrical = 0
cylangle = 0.0
if is_verbose():
print("S4SphereOpticalElement.get_optical_surface_instance(): R, cyl, cyl_angle, optical element, ",
radius, cylindrical, cylangle, surface_shape)
out = S4Conic.initialize_as_sphere_from_external_parameters(radius,
cylindrical=cylindrical,
cylangle=cylangle,
switch_convexity=switch_convexity,
)
if is_verbose(): print("Sphere ccc", out.ccc)
return out
[docs]class S4EllipsoidOpticalElementDecorator(S4CurvedOpticalElementDecorator):
"""
Creates the shadow4 optical element decorator for an Ellipsoid surface.
Parameters
----------
surface_calculation : int, optional
flag:
0 = SurfaceCalculation.INTERNAL,
1 = SurfaceCalculation.EXTERNAL.
is_cylinder : int, optional
flag:
0=No (there is revolution symmetry along Y)
1=Yes (flat surface along X or Y).
cylinder_direction : int (as defined by Direction), optional
TANGENTIAL = 0, SAGITTAL = 1.
convexity : int (as defined by Convexity), optional
NONE = -1, UPWARD = 0, DOWNWARD = 1.
min_axis : float, optional
For surface_calculation=0, The minor axis of the ellipsoid (2a).
maj_axis : float, optional
For surface_calculation=0, The major axis of the ellipsoid (2b)
pole_to_focus : float, optional
For surface_calculation=0, the p or q distance (from focus to center of the optical element).
p_focus : float, optional
For surface_calculation=1,2, the p distance (from source plane to center of the optical element).
q_focus : float, optional
For surface_calculation=1, the q distance (from the center of the optical element to the image plane).
grazing_angle : float, optional
For surface_calculation=1, the grazing angle in rad.
"""
def __init__(self,
surface_calculation=SurfaceCalculation.INTERNAL,
is_cylinder=False,
cylinder_direction=Direction.TANGENTIAL,
convexity=Convexity.UPWARD,
min_axis=0.0,
maj_axis=0.0,
pole_to_focus=0.0,
p_focus=0.0,
q_focus=0.0,
grazing_angle=0.0,
):
if surface_calculation == SurfaceCalculation.EXTERNAL:
if is_cylinder: curved_surface_shape = EllipticalCylinder.create_elliptical_cylinder_from_axes(min_axis, maj_axis, pole_to_focus, convexity, cylinder_direction)
else: curved_surface_shape = Ellipsoid.create_ellipsoid_from_axes(min_axis, maj_axis, pole_to_focus, convexity)
else:
if is_cylinder: curved_surface_shape = EllipticalCylinder.create_elliptical_cylinder_from_p_q(p_focus, q_focus, grazing_angle, convexity, cylinder_direction)
else: curved_surface_shape = Ellipsoid.create_ellipsoid_from_p_q(p_focus, q_focus, grazing_angle, convexity)
S4CurvedOpticalElementDecorator.__init__(self, surface_calculation, is_cylinder, curved_surface_shape)
[docs] def get_optical_surface_instance(self): # todo: update this one like hyperboloid
"""
Returns a shadow4 optical element object of type optical surface.
Returns
-------
instance of shadow4.s4_optical_surfaces.s4_conic.S4Conic
"""
surface_shape = self.get_surface_shape_instance()
switch_convexity = 0 if surface_shape.get_convexity() == Convexity.DOWNWARD else 1
if isinstance(surface_shape, EllipticalCylinder):
if is_verbose(): print("EllipticalCylinder optical element", surface_shape)
cylindrical = 1
cylangle = 0.0 if surface_shape.get_cylinder_direction() == Direction.TANGENTIAL else (0.5 * numpy.pi)
elif isinstance(surface_shape, Ellipsoid):
if is_verbose(): print("Ellipsoid optical element", surface_shape)
cylindrical = 0
cylangle = 0.0
out = S4Conic.initialize_as_ellipsoid_from_focal_distances(surface_shape.get_p_focus(),
surface_shape.get_q_focus(),
surface_shape.get_grazing_angle(),
cylindrical=cylindrical,
cylangle=cylangle,
switch_convexity=switch_convexity,
)
if is_verbose(): print("Ellipsoid ccc", out.ccc)
return out
[docs]class S4HyperboloidOpticalElementDecorator(S4CurvedOpticalElementDecorator):
"""
Creates the shadow4 optical element decorator for an Hyperboloid surface.
Parameters
----------
surface_calculation : int, optional
flag:
0 = SurfaceCalculation.INTERNAL,
1 = SurfaceCalculation.EXTERNAL.
is_cylinder : int, optional
flag:
0=No (there is revolution symmetry along Y)
1=Yes (flat surface along X or Y).
cylinder_direction : int (as defined by Direction), optional
NONE = -1, UPWARD = 0, DOWNWARD = 1.
convexity : int (as defined by Convexity), optional
NONE = -1, UPWARD = 0, DOWNWARD = 1.
min_axis : float, optional
For surface_calculation=0, The minor axis of the ellipsoid (2a).
maj_axis : float, optional
For surface_calculation=0, The major axis of the ellipsoid (2b)
pole_to_focus : float, optional
For surface_calculation=0, the p or q distance (from focus to center of the optical element).
p_focus : float, optional
For surface_calculation=1,2, the p distance (from source plane to center of the optical element).
q_focus : float, optional
For surface_calculation=1, the q distance (from the center of the optical element to the image plane).
grazing_angle : float, optional
For surface_calculation=1, the grazing angle in rad.
"""
def __init__(self,
surface_calculation=SurfaceCalculation.INTERNAL,
is_cylinder=False,
cylinder_direction=Direction.TANGENTIAL,
convexity=Convexity.UPWARD,
min_axis=0.0,
maj_axis=0.0,
pole_to_focus=0.0,
p_focus=0.0,
q_focus=0.0,
grazing_angle=0.0,
):
if surface_calculation == SurfaceCalculation.EXTERNAL:
if is_cylinder: curved_surface_shape = HyperbolicCylinder.create_hyperbolic_cylinder_from_axes(min_axis, maj_axis, pole_to_focus, convexity, cylinder_direction)
else: curved_surface_shape = Hyperboloid.create_hyperboloid_from_axes(min_axis, maj_axis, pole_to_focus, convexity)
else:
if is_cylinder: curved_surface_shape = HyperbolicCylinder.create_hyperbolic_cylinder_from_p_q(p_focus, q_focus, grazing_angle, convexity, cylinder_direction)
else: curved_surface_shape = Hyperboloid.create_hyperboloid_from_p_q(p_focus, q_focus, grazing_angle, convexity)
S4CurvedOpticalElementDecorator.__init__(self, surface_calculation, is_cylinder, curved_surface_shape)
[docs] def get_optical_surface_instance(self):
"""
Returns a shadow4 optical element object of type optical surface.
Returns
-------
instance of shadow4.s4_optical_surfaces.s4_conic.S4Conic
"""
surface_shape = self.get_surface_shape_instance()
switch_convexity = 0 if surface_shape.get_convexity() == Convexity.DOWNWARD else 1
if isinstance(surface_shape, HyperbolicCylinder):
if is_verbose(): print("HyperbolicCylinder optical element", surface_shape)
cylindrical = 1
cylangle = 0.0 if surface_shape.get_cylinder_direction() == Direction.TANGENTIAL else (0.5 * numpy.pi)
elif isinstance(surface_shape, Hyperboloid):
if is_verbose(): print("Hyperboloid optical element", surface_shape)
cylindrical = 0
cylangle = 0.0
out = S4Conic.initialize_as_hyperboloid_from_focal_distances(surface_shape.get_p_focus(),
surface_shape.get_q_focus(),
surface_shape.get_grazing_angle(),
cylindrical=cylindrical,
cylangle=cylangle,
switch_convexity=switch_convexity)
if is_verbose(): print("Hyperboloid ccc", out.ccc)
return out
[docs]class S4ToroidOpticalElementDecorator(S4CurvedOpticalElementDecorator):
"""
Creates the shadow4 optical element decorator for an Toroid surface.
Parameters
----------
surface_calculation : int, optional
flag:
0 = SurfaceCalculation.INTERNAL,
1 = SurfaceCalculation.EXTERNAL.
min_radius : float, optional
The minor axis of the toroid in m.
maj_radius : float, optional
The surface major radius in m. Note that this is the radius of the optical surface (it is not the radius
of the toroid).
f_torus : int, optional
........
p_focus : float, optional
For surface_calculation=1, the p distance (from source plane to center of the optical element).
q_focus : float, optional
For surface_calculation=1, the q distance (from the center of the optical element to the image plane).
grazing_angle : float, optional
For surface_calculation=1, the grazing angle in rad.
"""
def __init__(self,
surface_calculation=SurfaceCalculation.INTERNAL,
min_radius=0.0,
maj_radius=0.0,
f_torus=0,
p_focus=0.0,
q_focus=0.0,
grazing_angle=0.0,
):
if surface_calculation == SurfaceCalculation.EXTERNAL:
curved_surface_shape = Toroid.create_toroid_from_radii(min_radius, maj_radius)
else:
curved_surface_shape = Toroid.create_toroid_from_p_q(p_focus, q_focus, grazing_angle)
S4CurvedOpticalElementDecorator.__init__(self, surface_calculation, False, curved_surface_shape)
self._f_torus = f_torus
[docs] def get_optical_surface_instance(self):
"""
Returns a shadow4 optical element object of type optical surface.
Returns
-------
instance of shadow4.s4_optical_surfaces.s4_conic.S4Toroid
"""
surface_shape = self.get_surface_shape_instance()
if self._f_torus == 0:
r_maj = surface_shape.get_maj_radius() - surface_shape.get_min_radius()
elif self._f_torus == 1:
r_maj = surface_shape.get_maj_radius() + surface_shape.get_min_radius()
elif self._f_torus == 2:
r_maj = surface_shape.get_maj_radius() + surface_shape.get_min_radius()
elif self._f_torus == 3:
r_maj = surface_shape.get_maj_radius() - surface_shape.get_min_radius()
if is_verbose():
print("Toroidal optical element (syned stored, optical radii) %.12g %.12g" % (surface_shape.get_maj_radius(), surface_shape.get_min_radius()) )
print("Setting optical surface S4Toroid (toroid radii, not optical) r_maj=%.12g, r_min=%.12g, f_torus=%d" % (
r_maj,
surface_shape.get_min_radius(),
self._f_torus))
return S4Toroid(
r_maj=r_maj,
r_min=surface_shape.get_min_radius(),
f_torus=self._f_torus)
[docs]class S4ParaboloidOpticalElementDecorator(S4CurvedOpticalElementDecorator):
"""
Creates the shadow4 optical element decorator for an Paraboloid surface.
Parameters
----------
surface_calculation : int, optional
flag:
0 = SurfaceCalculation.INTERNAL,
1 = SurfaceCalculation.EXTERNAL.
is_cylinder : int, optional
flag:
0=No (there is revolution symmetry along Y)
1=Yes (flat surface along X or Y).
cylinder_direction : int (as defined by Direction), optional
NONE = -1, UPWARD = 0, DOWNWARD = 1.
convexity : int (as defined by Convexity), optional
NONE = -1, UPWARD = 0, DOWNWARD = 1.
parabola_parameter : float, optional
For surface_calculation=0, The parabola parameter PARAM (y^2 = 2 PARAM z)
at_infinity : int, optional
For surface_calculation=0, flag to indicate that
0: the source is at infinity (focusing paraboloid) = Side.SOURCE.
1: the image is at infinity (collimating paraboloid) = Side.IMAGE.
pole_to_focus : float, optional
For surface_calculation=0, the p or q distance (from focus to center of the optical element).
p_focus : float, optional
For surface_calculation=1, the q distance (from source plane to the center of the optical element).
q_focus : float, optional
For surface_calculation=1, the q distance (from the center of the optical element to the image plane).
grazing_angle : float, optional
For surface_calculation=1, the grazing angle in rad.
"""
def __init__(self,
surface_calculation=SurfaceCalculation.INTERNAL,
is_cylinder=False,
cylinder_direction=Direction.TANGENTIAL,
convexity=Convexity.UPWARD,
parabola_parameter=0.0,
at_infinity=Side.SOURCE,
pole_to_focus=0.0,
p_focus=0.0,
q_focus=0.0,
grazing_angle=0.0,
):
if surface_calculation == SurfaceCalculation.EXTERNAL:
if is_cylinder:
curved_surface_shape = ParabolicCylinder.create_parabolic_cylinder_from_parabola_parameter(
parabola_parameter, at_infinity, pole_to_focus, convexity, cylinder_direction)
else:
curved_surface_shape = Paraboloid.create_paraboloid_from_parabola_parameter(
parabola_parameter, at_infinity, pole_to_focus, convexity)
else:
if is_cylinder:
curved_surface_shape = ParabolicCylinder.create_parabolic_cylinder_from_p_q(
p_focus, q_focus, grazing_angle, at_infinity, convexity, cylinder_direction)
else:
curved_surface_shape = Paraboloid.create_paraboloid_from_p_q(
p_focus, q_focus, grazing_angle, at_infinity, convexity)
S4CurvedOpticalElementDecorator.__init__(self, surface_calculation, is_cylinder, curved_surface_shape)
[docs] def get_optical_surface_instance(self):
"""
Returns a shadow4 optical element object of type optical surface.
Returns
-------
instance of shadow4.s4_optical_surfaces.s4_conic.S4Conic
"""
surface_shape = self.get_surface_shape_instance()
switch_convexity = 0 if surface_shape.get_convexity() == Convexity.DOWNWARD else 1
if surface_shape.get_at_infinity() == Side.SOURCE:
p = 1e20
q = surface_shape.get_pole_to_focus()
else:
q = 1e20
p = surface_shape.get_pole_to_focus()
if isinstance(surface_shape, ParabolicCylinder):
if is_verbose(): print("ParabolicCylinder optical element", surface_shape)
cylindrical = 1
cylangle = 0.0 if surface_shape.get_cylinder_direction() == Direction.TANGENTIAL else (0.5 * numpy.pi)
elif isinstance(surface_shape, Paraboloid):
if is_verbose(): print("Paraboloid optical element", surface_shape)
cylindrical = 0
cylangle = 0.0
out = S4Conic.initialize_as_paraboloid_from_focal_distances(p, q, surface_shape.get_grazing_angle(), cylindrical=cylindrical, cylangle=cylangle, switch_convexity=switch_convexity)
if is_verbose(): print("Paraboloid ccc", out.ccc)
return out
[docs]class S4ConicOpticalElementDecorator(S4CurvedOpticalElementDecorator):
def __init__(self, conic_coefficients=[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0,0.0]):
"""
Creates the shadow4 optical element decorator for a Conic surface.
Parameters
----------
conic_coefficients : list, ndarray, optional
The list of the 10 conic coefficients.
"""
S4CurvedOpticalElementDecorator.__init__(
self,
surface_calculation=SurfaceCalculation.INTERNAL,
is_cylinder=False,
curved_surface_shape=None if conic_coefficients is None else Conic(conic_coefficients=conic_coefficients))
[docs] def get_optical_surface_instance(self):
"""
Returns a shadow4 optical element object of type optical surface.
Returns
-------
instance of shadow4.s4_optical_surfaces.s4_conic.S4Conic
"""
surface_shape = self.get_surface_shape_instance()
out = S4Conic.initialize_from_coefficients(surface_shape.get_conic_coefficients())
if is_debug():
print("Conic optical element")
print("Conic ccc", out.ccc)
return out
[docs]class S4NumericalMeshOpticalElementDecorator(S4CurvedOpticalElementDecorator):
"""
Creates the shadow4 optical element decorator for a Mesh surface.
Parameters
----------
xx : ndarray, optional
the 1D array with the X points.
yy : ndarray, optional
the 1D array with the Y points.
zz : ndarray, optional
the 2D [shape Nx,Ny] array with the Z points.
surface_data_file : str, optional
the name of the h5 file with the mesh.
"""
def __init__(self, xx=None, yy=None, zz=None, surface_data_file=None):
S4CurvedOpticalElementDecorator.__init__(self,
surface_calculation=SurfaceCalculation.INTERNAL,
is_cylinder=False,
curved_surface_shape = NumericalMesh(xx, yy, zz, surface_data_file))
[docs] def get_optical_surface_instance(self):
"""
Returns a shadow4 optical element object of type optical surface.
Returns
-------
instance of shadow4.s4_optical_surfaces.s4_conic.S4Mesh
"""
surface_shape = self.get_surface_shape_instance()
if is_verbose(): print("SurfaceData optical element")
numerical_mesh = S4Mesh()
if surface_shape.has_surface_data(): numerical_mesh.load_surface_data(surface_shape)
elif surface_shape.has_surface_data_file():
filename, file_extension = os.path.splitext(surface_shape._surface_data_file)
if file_extension.lower() in [".h5", ".hdf", ".hdf5"]: numerical_mesh.load_h5file(surface_shape._surface_data_file)
else: numerical_mesh.load_file(surface_shape._surface_data_file) # 3 columns ASCII
return numerical_mesh
##################################################
# LENS OPTICAL ELEMENTS
##################################################
[docs]class S4RefractiveLensOpticalElementDecorator(S4CurvedOpticalElementDecorator):
"""
Creates the shadow4 optical element decorator for a Refractive lens.
Parameters
----------
surface_shape : int, optional
Flag for the single lens surface shape: 0=plane, 1=sphere, 2=parabola, 3=conic coefficients
convex_to_the_beam : int, optional
Flag for convexity of the first interface exposed to the beam
For surface_shape (1,2): 0=No, 1=Yes, or in other words 0=Concave, 1=Convex
cylinder_angle : int, optional
Flag for cylindrical symmetry.
For surface_shape (1,2): 0=not cylindricaL, 1=meridional 2=sagittal
ri_calculation_mode : int, optional
Flag for the used source of refraction indices and absorption coefficients:
0=User
1=prerefl file
2=direct calculation using xraylib
3=direct calculation using dabax
prerefl_file : str, optional
For ri_calculation_mode=0: file name (from prerefl) to get the refraction index.
refraction_index : float, optional
For ri_calculation_mode=1: the real part of the refraction coefficient Real[n].
attenuation_coefficient : float, optional
For ri_calculation_mode=1: the linear absorption coefficient, in cm^-1 (real)..=
dabax : None or instance of DabaxXraylib,
The pointer to the dabax library (used for f_r_ind > 6).
radius : float, optional
For surface_shape=(1,2): lens radius [m] (for spherical, or radius at the tip for paraboloid).
conic_coefficients1 : list or ndarray, optional
For surface_shape = 3: the 10 conic coefficients of the first refractive interface.
conic_coefficients2 : list or ndarray, optional
For surface_shape = 3: the 10 conic coefficients of the second refractive interface.
"""
def __init__(self,
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 cm^-1 (real)
density=1.0,
dabax=None,
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
):
conic_coefficients = self._get_conic_coefficients(surface_shape,
radius,
cylinder_angle,
convex_to_the_beam,
conic_coefficients1,
conic_coefficients2)
if surface_shape == 0:
if conic_coefficients1 is None: conic_coefficients1 = [0, 0, 0, 0, 0, 0, 0, 0, -1, 0]
if conic_coefficients2 is None: conic_coefficients2 = [0, 0, 0, 0, 0, 0, 0, 0, -1, 0]
curved_surface_shape = [Conic(conic_coefficients=conic_coefficients1),
Conic(conic_coefficients=conic_coefficients2)]
else:
curved_surface_shape = [Conic(conic_coefficients=conic_coefficients[0]),
Conic(conic_coefficients=conic_coefficients[1])]
S4CurvedOpticalElementDecorator.__init__(self,
surface_calculation=SurfaceCalculation.EXTERNAL,
curved_surface_shape=curved_surface_shape)
self._ri_calculation_mode = ri_calculation_mode
self._prerefl_file = prerefl_file
self._refraction_index = refraction_index
self._attenuation_coefficient = attenuation_coefficient
self._density = density
self._dabax = dabax
def _get_conic_coefficients(self, surface_shape, radius, cylinder_angle, convex_to_the_beam, conic_coefficients1, conic_coefficients2):
if surface_shape == 0: conic_coefficients_1 = [0, 0, 0, 0, 0, 0, 0, 0, -1, 0]
elif surface_shape == 1: conic_coefficients_1 = [1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, -2.0 * radius, 0.0]
elif surface_shape == 2: conic_coefficients_1 = [1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -2.0 * radius, 0.0]
elif surface_shape == 3:
if conic_coefficients1 is None:
conic_coefficients_1 = [0, 0, 0, 0, 0, 0, 0, 0, -1, 0]
else:
conic_coefficients_1 = conic_coefficients1.copy()
else: return None
if surface_shape == 3:
if conic_coefficients2 is None:
conic_coefficients_2 = [0, 0, 0, 0, 0, 0, 0, 0, -1, 0]
else:
conic_coefficients_2 = conic_coefficients2.copy()
else:
if cylinder_angle == 1: conic_coefficients_1[0] = conic_coefficients_1[3] = conic_coefficients_1[5] = conic_coefficients_1[6] = 0
elif cylinder_angle == 2: conic_coefficients_1[1] = conic_coefficients_1[3] = conic_coefficients_1[4] = conic_coefficients_1[7] = 0
if convex_to_the_beam == 1: conic_coefficients_1[8] *= -1
conic_coefficients_2 = conic_coefficients_1.copy()
conic_coefficients_2[8] *= -1
return [conic_coefficients_1, conic_coefficients_2]
[docs] def get_optical_surface_instance(self):
"""
Returns a shadow4 optical element object of type optical surface.
Returns
-------
list
instances of shadow4.s4_optical_surfaces.s4_conic.S4Conic
"""
surface_shapes = self.get_surface_shape_instance()
c1 = S4Conic.initialize_from_coefficients(numpy.array(surface_shapes[0].get_conic_coefficients()))
c2 = S4Conic.initialize_from_coefficients(numpy.array(surface_shapes[1].get_conic_coefficients()))
if is_verbose():
print("interface 1: conic ccc", c1.ccc)
print("interface 2: conic ccc", c2.ccc)
return [c1, c2]
if __name__ == "__main__":
p = S4PlaneOpticalElementDecorator()
print(p.get_info())
assert(isinstance(p.get_surface_shape_instance(), Plane))
assert(isinstance(p.get_optical_surface_instance(), S4Conic))
print(SurfaceCalculation.INTERNAL, Direction.TANGENTIAL, Convexity.DOWNWARD)
p = S4SphereOpticalElementDecorator(
surface_calculation = SurfaceCalculation.EXTERNAL, # external=1, internal=0
is_cylinder = False,
cylinder_direction = Direction.TANGENTIAL,
convexity = Convexity.DOWNWARD, # upward=0, downward=1
radius = 0.111,
p_focus = 0.0,
q_focus = 0.0,
grazing_angle = 0.0)
assert(isinstance(p.get_surface_shape_instance(), Sphere))
assert(isinstance(p.get_optical_surface_instance(), S4Conic))
assert(p.get_optical_surface_instance().get_coefficients()[8] == -0.222)
print("radius: ", p.get_surface_shape_instance().get_radius())
p = S4SphereOpticalElementDecorator(
surface_calculation = SurfaceCalculation.INTERNAL, # external=1, internal=0
is_cylinder = False,
cylinder_direction = Direction.TANGENTIAL,
convexity = Convexity.DOWNWARD, # upward=0, downward=1
radius = 0,
p_focus = 10.0,
q_focus = 5.0,
grazing_angle = 0.003)
assert(isinstance(p.get_surface_shape_instance(), Sphere))
assert(isinstance(p.get_optical_surface_instance(), S4Conic))
radius = 2 / numpy.sin(0.003) / (1/10. + 1/5.)
print((-2 * radius), p.get_optical_surface_instance().get_coefficients()[8])
assert(numpy.abs(p.get_optical_surface_instance().get_coefficients()[8] - (-2 * radius)) < 1e-8)
print("radius: ", p.get_surface_shape_instance().get_radius(), radius)
p = S4EllipsoidOpticalElementDecorator(
surface_calculation = SurfaceCalculation.INTERNAL, # external=1, internal=0
is_cylinder = False,
cylinder_direction = Direction.TANGENTIAL,
convexity = Convexity.DOWNWARD, # upward=0, downward=1
min_axis=0.0,
maj_axis=0.0,
pole_to_focus=0.0,
p_focus = 100.0,
q_focus = 1000.0,
grazing_angle = 20.943951e-3)
assert(isinstance(p.get_surface_shape_instance(), Ellipsoid))
assert(isinstance(p.get_optical_surface_instance(), S4Conic))
print("axes: ", p.get_surface_shape_instance().get_axes())
print("semi-axes a,b: ", p.get_surface_shape_instance().get_a(), p.get_surface_shape_instance().get_b())
print("p_focus: ", p.get_surface_shape_instance().get_p_focus(), )
print("grazing_angle: ", p.get_surface_shape_instance().get_grazing_angle(), )
p = S4EllipsoidOpticalElementDecorator(
surface_calculation = SurfaceCalculation.EXTERNAL, # external=1, internal=0
is_cylinder = False,
cylinder_direction = Direction.TANGENTIAL,
convexity = Convexity.DOWNWARD, # upward=0, downward=1
min_axis=13.245149294268580,
maj_axis=1100,
pole_to_focus=100,
p_focus = 0.0,
q_focus = 0.0,
grazing_angle = 0)
assert(isinstance(p.get_surface_shape_instance(), Ellipsoid))
assert(isinstance(p.get_optical_surface_instance(), S4Conic))
print("axes: ", p.get_surface_shape_instance().get_axes())
print("semi-axes a,b: ", p.get_surface_shape_instance().get_a(), p.get_surface_shape_instance().get_b())
print("p_focus: ", p.get_surface_shape_instance().get_p_focus(), )
print("grazing_angle: ", p.get_surface_shape_instance().get_grazing_angle(), )
p = S4HyperboloidOpticalElementDecorator(
surface_calculation = SurfaceCalculation.INTERNAL, # external=1, internal=0
is_cylinder = False,
cylinder_direction = Direction.TANGENTIAL,
convexity = Convexity.DOWNWARD, # upward=0, downward=1
min_axis=0.0,
maj_axis=0.0,
pole_to_focus=0.0,
p_focus = 100.0,
q_focus = 1000.0,
grazing_angle = 20e-3)
assert(isinstance(p.get_surface_shape_instance(), Hyperboloid))
assert(isinstance(p.get_optical_surface_instance(), S4Conic))
print("axes: ", p.get_surface_shape_instance().get_axes())
print("semi-axes a,b: ", p.get_surface_shape_instance().get_a(), p.get_surface_shape_instance().get_b())
print("p_focus: ", p.get_surface_shape_instance().get_p_focus(), )
print("grazing_angle: ", p.get_surface_shape_instance().get_grazing_angle(), )
p = S4HyperboloidOpticalElementDecorator(
surface_calculation = SurfaceCalculation.EXTERNAL, # external=1, internal=0
is_cylinder = False,
cylinder_direction = Direction.TANGENTIAL,
convexity = Convexity.DOWNWARD, # upward=0, downward=1
min_axis=2*0.043058,
maj_axis=2*0.951524,
pole_to_focus=100,
p_focus = 100.0,
q_focus = 1000.0,
grazing_angle = 20.943951e-3)
assert(isinstance(p.get_surface_shape_instance(), Hyperboloid))
assert(isinstance(p.get_optical_surface_instance(), S4Conic))
print("axes: ", p.get_surface_shape_instance().get_axes())
print("semi-axes a,b: ", p.get_surface_shape_instance().get_a(), p.get_surface_shape_instance().get_b())
print("p_focus: ", p.get_surface_shape_instance().get_p_focus(), )
print("grazing_angle: ", p.get_surface_shape_instance().get_grazing_angle(), )
p = S4ToroidOpticalElementDecorator(
surface_calculation = SurfaceCalculation.INTERNAL, # external=1, internal=0
min_radius=0.0,
maj_radius=0.0,
f_torus=0,
p_focus = 10.0,
q_focus = 6.0,
grazing_angle = 0.020943951)
assert(isinstance(p.get_surface_shape_instance(), Toroid))
assert(isinstance(p.get_optical_surface_instance(), S4Toroid))
print("radii (syned stored, optical): ",
p.get_surface_shape_instance().get_min_radius(),
p.get_surface_shape_instance().get_maj_radius())
p = S4ToroidOpticalElementDecorator(
surface_calculation = SurfaceCalculation.EXTERNAL, # external=1, internal=0
min_radius=0.157068,
maj_radius=358.1248036445412-0.157068,
f_torus=0,
p_focus = 0.0,
q_focus = 0.0,
grazing_angle = 0.0)
assert(isinstance(p.get_surface_shape_instance(), Toroid))
assert(isinstance(p.get_optical_surface_instance(), S4Toroid))
print("radii (syned stored, optical): ",
p.get_surface_shape_instance().get_min_radius(),
p.get_surface_shape_instance().get_maj_radius())
p = S4ParaboloidOpticalElementDecorator(
surface_calculation = SurfaceCalculation.INTERNAL, # external=1, internal=0
is_cylinder = False,
cylinder_direction = Direction.TANGENTIAL,
convexity = Convexity.DOWNWARD, # upward=0, downward=1
parabola_parameter=0.0,
at_infinity=Side.SOURCE,
pole_to_focus=0.0,
p_focus = 0.0,
q_focus = 10.0,
grazing_angle = 20.943951e-3)
assert(isinstance(p.get_surface_shape_instance(), Paraboloid))
assert(isinstance(p.get_optical_surface_instance(), S4Conic))
print("parabola parameter: ", p.get_surface_shape_instance().get_parabola_parameter())
print("parabola at_infinity (0=Source,1=Image): ", p.get_surface_shape_instance().get_at_infinity())
print("grazing angle: ", p.get_surface_shape_instance().get_grazing_angle())
p = S4ParaboloidOpticalElementDecorator(
surface_calculation = SurfaceCalculation.EXTERNAL, # external=1, internal=0
is_cylinder = False,
cylinder_direction = Direction.TANGENTIAL,
convexity = Convexity.DOWNWARD, # upward=0, downward=1
parabola_parameter=0.008771698991373174,
at_infinity=Side.SOURCE,
pole_to_focus=10.0,
p_focus = 0.0,
q_focus = 0.0,
grazing_angle = 0)
assert(isinstance(p.get_surface_shape_instance(), Paraboloid))
assert(isinstance(p.get_optical_surface_instance(), S4Conic))
print("parabola parameter: ", p.get_surface_shape_instance().get_parabola_parameter())
print("parabola at_infinity (0=Source,1=Image): ", p.get_surface_shape_instance().get_at_infinity())
print("grazing angle: ", p.get_surface_shape_instance().get_grazing_angle())
p = S4RefractiveLensOpticalElementDecorator()
print(p.get_optical_surface_instance())
# assert(isinstance(p.get_surface_shape_instance(), Paraboloid))
# assert(isinstance(p.get_optical_surface_instance(), S4Conic))