"""
S4 refractive interface.
"""
import numpy
from syned.beamline.element_coordinates import ElementCoordinates
from syned.beamline.optical_elements.refractors.interface import Interface
from syned.beamline.shape import Rectangle, Ellipse
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.physical_models.prerefl.prerefl import PreRefl
[docs]class S4Interface(Interface):
"""
Shadow4 refractive interface class
This is a base class for refractors.
Use derived classes for Conic or other curved surfaces.
Constructor.
Parameters
----------
name : str, optional
The name of the mirror.
boundary_shape : instance of BoundaryShape, optional
The boundary shape of the mirror.
surface_shape : instance of SurfaceShape, optional
The surface shape of the mirror.
material_object : str, optional
string with material symbol or formula (used when f_r_ind>3).
material_image : str, optional
string with material symbol or formula (used when f_r_ind>3).
density_object : float, optional
density for material_object (used when f_r_ind>3).
density_image : float, optional
density for material_image (used when f_r_ind>3).
f_r_ind : int, optional
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.
- (4) xraylib in object space, constant value in image space,
- (5) constant value in object space, xraylib in image space,
- (6) xraylib in both object and image space.
- (7) dabax in object space, constant value in image space,
- (8) constant value in object space, dabax in image space,
- (9) dabax in both object and image space.
r_ind_obj : float or numpy array
(for f_r_ind=0,2): index of refraction (real) in object space.
r_ind_ima : float or numpy array
(for f_r_ind=0,1): index of refraction (real) in image space.
r_attenuation_obj : float or numpy array
(for f_r_ind=0,2): attenuation coefficient in object space. Units of m^(-1)
r_attenuation_ima : float or numpy array
(for f_r_ind=0,1): attenuation coefficient in image space. Units of m^(-1)
file_r_ind_obj : str, optional
(for f_r_ind=1,3): file generated by PREREFL preprocessor.
file_r_ind_ima : str, optional
(for f_r_ind=2,3): file generated by PREREFL preprocessor.
dabax : None or instance of DabaxXraylib,
The pointer to the dabax library (used for f_r_ind > 6).
Returns
-------
instance of S4Interface.
"""
def __init__(self,
name = "Undefined",
boundary_shape = None,
surface_shape = None,
material_object = None,
material_image = None,
density_object = 1.0,
density_image = 1.0,
f_r_ind = 0,
r_ind_obj = 1.0,
r_ind_ima = 1.0,
r_attenuation_obj = 0.0,
r_attenuation_ima = 0.0,
file_r_ind_obj = "",
file_r_ind_ima = "",
dabax = None,
):
Interface.__init__(self,
name=name,
surface_shape=surface_shape,
boundary_shape=boundary_shape,
material_object=material_object,
material_image=material_image,
)
self._f_r_ind = f_r_ind
self._r_ind_obj = r_ind_obj
self._r_ind_ima = r_ind_ima
self._r_attenuation_obj = r_attenuation_obj
self._r_attenuation_ima = r_attenuation_ima
self._file_r_ind_obj = file_r_ind_obj
self._file_r_ind_ima = file_r_ind_ima
self._density_object = density_object
self._density_image = density_image
self._dabax = dabax
[docs] def get_info(self):
"""
Returns the specific information of the S4 refractive interface optical element.
Returns
-------
str
"""
txt = "\n\n"
txt += "REFRACTOR (INTERFACE)\n"
txt += "\n"
"Source of material refraction indices:\n"
if self._f_r_ind == 0:
txt += " constant value in both object and image spaces\n"
txt += " index of refraction in object space: %f \n" % self._r_ind_obj
txt += " attenuation coeff in object space: %f \n" % self._r_attenuation_obj
txt += " index of refraction in image space: %f \n" % self._r_ind_ima
txt += " attenuation coeff in image space: %f \n" % self._r_attenuation_ima
elif self._f_r_ind == 1:
txt += " file in object space, constant value in image space\n"
txt += " file generated by prerefl for object space: %s \n" % self._file_r_ind_obj
txt += " index of refraction in image space: %f \n" % self._r_ind_ima
txt += " attenuation coeff in image space: %f \n" % self._r_attenuation_ima
elif self._f_r_ind == 2:
txt += " constant value in object space, file in image space\n"
txt += " index of refraction in object space: %f \n" % self._r_ind_obj
txt += " attenuation coeff in object space: %f \n" % self._r_attenuation_obj
txt += " file generated by prerefl for image space: %s \n" % self._file_r_ind_ima
elif self._f_r_ind == 3:
txt += " file in both object and image space\n"
txt += " file generated by prerefl for object space: %s \n" % self._file_r_ind_obj
txt += " file generated by prerefl for image space: %s \n" % self._file_r_ind_ima
elif self._f_r_ind == 4:
txt += " xraylib in object space, constant value in image space\n"
txt += " index of refraction in image space: %f \n" % self._r_ind_ima
txt += " attenuation coeff in image space: %f \n" % self._r_attenuation_ima
elif self._f_r_ind == 5:
txt += " constant value in object space, xraylib in image space\n"
txt += " index of refraction in object space: %f \n" % self._r_ind_obj
txt += " attenuation coeff in object space: %f \n" % self._r_attenuation_obj
elif self._f_r_ind == 6:
txt += " xraylib in both object and image space\n"
elif self._f_r_ind == 7:
txt += " dabax in object space, constant value in image space\n"
txt += " index of refraction in image space: %f \n" % self._r_ind_ima
txt += " attenuation coeff in image space: %f \n" % self._r_attenuation_ima
elif self._f_r_ind == 8:
txt += " constant value in object space, dabax in image space\n"
txt += " index of refraction in object space: %f \n" % self._r_ind_obj
txt += " attenuation coeff in object space: %f \n" % self._r_attenuation_obj
elif self._f_r_ind == 9:
txt += " dabax in both object and image space\n"
txt += "\n"
ss = self.get_surface_shape()
if ss is None:
txt += "Surface shape is: Plane (** UNDEFINED?? **)\n"
else:
txt += "Surface shape is: %s\n" % ss.__class__.__name__
txt += "\nParameters:\n %s\n" % ss.info()
txt += self.get_optical_surface_instance().info() + "\n"
boundary = self.get_boundary_shape()
if boundary is None:
txt += "Surface boundaries not considered (infinite)"
else:
txt += "Surface boundaries are: %s\n" % boundary.__class__.__name__
txt += " Limits: " + repr( boundary.get_boundaries()) + "\n"
txt += boundary.info()
return txt
[docs] def apply_interface_refraction(self, **kwargs):
raise Exception("To be implemented in the children class")
[docs] def to_python_code(self, **kwargs):
"""
Creates the python code for defining the element.
Parameters
----------
**kwargs
Returns
-------
str
Python code.
"""
raise Exception("To be implemented in the children class")
[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 = "" # "\nfrom shadow4.beamline.optical_elements.mirrors.s4_plane_mirror import S4PlaneMirror"
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, 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 get_refraction_indices(self, photon_energy_eV=None):
"""
Calculates the real part refraction indices for a given energy or energy array from the input data.
Parameters
----------
photon_energy_eV : float or numpy array, optional
The photon energy in eV.
Returns
-------
tuple
(refraction_index_object, refraction_index_image) with the real part of the refraction indices.
"""
# 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 = "/nobackup/gurb1/srio/Oasys/Be.dat", # (for f_r_ind=2,3): file generated by PREREFL
if self._f_r_ind == 0:
refraction_index_object = self._r_ind_obj
refraction_index_image = self._r_ind_ima
elif self._f_r_ind == 1:
preprefl1 = PreRefl()
preprefl1.read_preprocessor_file(self._file_r_ind_obj)
refraction_index_object = (preprefl1.get_refraction_index(photon_energy_eV)).real
refraction_index_image = self._r_ind_ima * numpy.ones_like(refraction_index_object)
elif self._f_r_ind == 2:
preprefl2 = PreRefl()
preprefl2.read_preprocessor_file(self._file_r_ind_ima)
refraction_index_image = (preprefl2.get_refraction_index(photon_energy_eV)).real
refraction_index_object = self._r_ind_obj * numpy.ones_like(refraction_index_image)
elif self._f_r_ind == 3:
preprefl1 = PreRefl()
preprefl2 = PreRefl()
preprefl1.read_preprocessor_file(self._file_r_ind_obj)
preprefl2.read_preprocessor_file(self._file_r_ind_ima)
refraction_index_object = (preprefl1.get_refraction_index(photon_energy_eV)).real
refraction_index_image = (preprefl2.get_refraction_index(photon_energy_eV)).real
elif self._f_r_ind == 4:
refraction_index_object = PreRefl.get_refraction_index_real_external_xraylib(material=self.get_material_object(),
photon_energy_ev=photon_energy_eV,
density=self._density_object)
refraction_index_image = self._r_ind_ima * numpy.ones_like(refraction_index_object)
elif self._f_r_ind == 5:
refraction_index_image = PreRefl.get_refraction_index_real_external_xraylib(material=self.get_material_image(),
photon_energy_ev=photon_energy_eV,
density=self._density_image)
refraction_index_object = self._r_ind_obj * numpy.ones_like(refraction_index_image)
elif self._f_r_ind == 6:
refraction_index_object = PreRefl.get_refraction_index_real_external_xraylib(material=self.get_material_object(),
photon_energy_ev=photon_energy_eV,
density=self._density_object)
refraction_index_image = PreRefl.get_refraction_index_real_external_xraylib(material=self.get_material_image(),
photon_energy_ev=photon_energy_eV,
density=self._density_image)
elif self._f_r_ind == 7:
refraction_index_object = PreRefl.get_refraction_index_real_external_dabax(material=self.get_material_object(),
photon_energy_ev=photon_energy_eV,
density=self._density_object,
dabax=self._dabax)
refraction_index_image = self._r_ind_ima * numpy.ones_like(refraction_index_object)
elif self._f_r_ind == 8:
refraction_index_image = PreRefl.get_refraction_index_real_external_dabax(material=self.get_material_image(),
photon_energy_ev=photon_energy_eV,
density=self._density_image,
dabax=self._dabax)
refraction_index_object = self._r_ind_obj * numpy.ones_like(refraction_index_image)
elif self._f_r_ind == 9:
refraction_index_object = PreRefl.get_refraction_index_real_external_dabax(material=self.get_material_object(),
photon_energy_ev=photon_energy_eV,
density=self._density_object,
dabax=self._dabax)
refraction_index_image = PreRefl.get_refraction_index_real_external_dabax(material=self.get_material_image(),
photon_energy_ev=photon_energy_eV,
density=self._density_image,
dabax=self._dabax)
return refraction_index_object, refraction_index_image
[docs] def get_attenuation_coefficients(self, photon_energy_eV=None):
"""
Calculates the attenuation coefficients for a given energy or energy array from the input data.
Parameters
----------
photon_energy_eV : float or numpy array, optional
The photon energy in eV.
Returns
-------
tuple
(attenuation_coefficient_object, attenuation_coefficient_image) with the real part of the refraction indices.
"""
# 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 = "/nobackup/gurb1/srio/Oasys/Be.dat", # (for f_r_ind=2,3): file generated by PREREFL
if self._f_r_ind == 0:
attenuation_coefficient_object = self._r_attenuation_obj # already in m^-1
attenuation_coefficient_image = self._r_attenuation_ima
elif self._f_r_ind == 1:
preprefl1 = PreRefl()
preprefl1.read_preprocessor_file(self._file_r_ind_obj)
attenuation_coefficient_object = (preprefl1.get_attenuation_coefficient(photon_energy_eV)) * 100 # in m^-1
attenuation_coefficient_image = self._r_attenuation_ima * numpy.ones_like(attenuation_coefficient_object)
elif self._f_r_ind == 2:
preprefl2 = PreRefl()
preprefl2.read_preprocessor_file(self._file_r_ind_ima)
attenuation_coefficient_image = (preprefl2.get_attenuation_coefficient(photon_energy_eV)) * 100
attenuation_coefficient_object = self._r_attenuation_obj * numpy.ones_like(attenuation_coefficient_image)
elif self._f_r_ind == 3:
preprefl1 = PreRefl()
preprefl2 = PreRefl()
preprefl1.read_preprocessor_file(self._file_r_ind_obj)
preprefl2.read_preprocessor_file(self._file_r_ind_ima)
attenuation_coefficient_object = (preprefl1.get_attenuation_coefficient(photon_energy_eV)) * 100
attenuation_coefficient_image = (preprefl2.get_attenuation_coefficient(photon_energy_eV)) * 100
elif self._f_r_ind == 4:
attenuation_coefficient_object = PreRefl.get_attenuation_coefficient_external_xraylib(
photon_energy_ev=photon_energy_eV,
material=self.get_material_object(),
density=self._density_object) * 100 # in m^-1
attenuation_coefficient_image = self._r_attenuation_ima * numpy.ones_like(attenuation_coefficient_object)
elif self._f_r_ind == 5:
attenuation_coefficient_image = PreRefl.get_attenuation_coefficient_external_xraylib(
photon_energy_ev=photon_energy_eV,
material=self.get_material_image(),
density=self._density_image) * 100 # in m^-1
attenuation_coefficient_object = self._r_attenuation_obj * numpy.ones_like(attenuation_coefficient_image)
elif self._f_r_ind == 6:
attenuation_coefficient_object = PreRefl.get_attenuation_coefficient_external_xraylib(
photon_energy_ev=photon_energy_eV,
material=self.get_material_object(),
density=self._density_object) * 100 # in m^-1
attenuation_coefficient_image = PreRefl.get_attenuation_coefficient_external_xraylib(
photon_energy_ev=photon_energy_eV,
material=self.get_material_image(),
density=self._density_image) * 100 # in m^-1
elif self._f_r_ind == 7:
attenuation_coefficient_object = PreRefl.get_attenuation_coefficient_external_dabax(
photon_energy_ev=photon_energy_eV,
material=self.get_material_object(),
density=self._density_object,
dabax=self._dabax) * 100 # in m^-1
attenuation_coefficient_image = self._r_attenuation_ima * numpy.ones_like(attenuation_coefficient_object)
elif self._f_r_ind == 8:
attenuation_coefficient_image = PreRefl.get_attenuation_coefficient_external_dabax(
photon_energy_ev=photon_energy_eV,
material=self.get_material_image(),
density=self._density_image,
dabax=self._dabax) * 100 # in m^-1
attenuation_coefficient_object = self._r_attenuation_obj * numpy.ones_like(attenuation_coefficient_image)
elif self._f_r_ind == 9:
attenuation_coefficient_object = PreRefl.get_attenuation_coefficient_external_dabax(
photon_energy_ev=photon_energy_eV,
material=self.get_material_object(),
density=self._density_object,
dabax=self._dabax) * 100 # in m^-1
attenuation_coefficient_image = PreRefl.get_attenuation_coefficient_external_dabax(
photon_energy_ev=photon_energy_eV,
material=self.get_material_image(),
density=self._density_image,
dabax=self._dabax) * 100 # in m^-1
return attenuation_coefficient_object, attenuation_coefficient_image
def _apply_interface_refraction(self, beam,
refraction_index_object, refraction_index_image, mu_object,
apply_attenuation=1):
sur = self.get_optical_surface_instance()
footprint, normal = sur.apply_refraction_on_beam(beam,
refraction_index_object, refraction_index_image,
apply_attenuation=apply_attenuation,
linear_attenuation_coefficient=mu_object)
return footprint, normal
def _get_dabax_txt(self):
if self._f_r_ind > 6:
if isinstance(self._dabax, DabaxXraylib):
dabax_txt = 'DabaxXraylib(file_f1f2="%s", file_CrossSec="%s")' % (self._dabax.get_file_f1f2(), self._dabax.get_file_CrossSec())
else:
dabax_txt = "DabaxXraylib()"
else:
dabax_txt = "None"
return dabax_txt
[docs]class S4InterfaceElement(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.
input_beam : instance of S4Beam, optional
The S4 incident beam.
Returns
-------
instance of S4InterfaceElement.
"""
def __init__(self,
optical_element : S4Interface = None,
coordinates : ElementCoordinates = None,
movements: S4BeamlineElementMovements = None,
input_beam : S4Beam = None):
super().__init__(optical_element=optical_element if optical_element is not None else S4Interface(),
coordinates=coordinates if coordinates is not None else ElementCoordinates(),
movements=movements,
input_beam=input_beam)
self.__stored_optical_constants = None
[docs] def get_stored_optical_constants(self):
"""
When running trace_beam() the optical constants (refraction index and attenuation coefficients for media 1 and 2)
are calculated. They are stored for accelerating further calls. This method permits to retrieve the stored
optical constants.
Returns
-------
tuple
(n1, mu1m n2, mu2)
n1, n2: arrays with real part of the refraction indices for the object and image media, respectively.
mu1, mu2: arrays with attenuation coefficient in m^(-1) for the object and image media, respectively.
"""
return self.__stored_optical_constants
[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.
"""
flag_lost_value = params.get("flag_lost_value", -1)
reused_stored_optical_constants = params.get("reused_stored_optical_constants", None)
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()
soe = self.get_optical_element()
# retrieve and store optical constants
if reused_stored_optical_constants is not None:
n1, mu1, n2, mu2 = reused_stored_optical_constants
else:
energy1 = input_beam.get_photon_energy_eV()
n1, n2 = soe.get_refraction_indices(energy1)
mu1, mu2 = soe.get_attenuation_coefficients(energy1) # in m^-1
self.__stored_optical_constants = (n1, mu1, n2, mu2)
#
# put beam in mirror reference system
#
input_beam.rotate(alpha1, axis=2)
input_beam.rotate(theta_grazing1, axis=1)
input_beam.translation([0.0, -p * numpy.cos(theta_grazing1), p * numpy.sin(theta_grazing1)])
# mirror movement:
movements = self.get_movements()
if movements is not None:
if movements.f_move:
input_beam.rot_for(OFFX=movements.offset_x,
OFFY=movements.offset_y,
OFFZ=movements.offset_z,
X_ROT=movements.rotation_x,
Y_ROT=movements.rotation_y,
Z_ROT=movements.rotation_z)
#
# refract beam in the mirror surface
#
# TODO (maybe): no check for total reflection is done...
# TODO (maybe): implement correctly in shadow4 via Fresnel equations for the transmitted beam
footprint, normal = soe._apply_interface_refraction(input_beam, n1, n2, mu1, apply_attenuation=1)
#
# apply mirror boundaries
#
footprint.apply_boundaries_syned(soe.get_boundary_shape(), flag_lost_value=flag_lost_value)
#
# from element reference system to image plane
#
output_beam = footprint.duplicate()
output_beam.change_to_image_reference_system(theta_grazing2, q,
refraction_index=n2,
apply_attenuation=1,
linear_attenuation_coefficient=mu2)
return output_beam, footprint
if __name__ == "__main__":
i = S4Interface()
print(i.info())
print(i.get_surface_shape())
e = S4InterfaceElement(optical_element=i)
# print(i.to_python_code())