Source code for shadow4.beamline.optical_elements.absorbers.s4_screen

"""

The S4 screen optical element: it deals with screens, slits, beam-stoppers and absorbers (as in shadow3).

Notes
-----
This is a stand-alone optical element (contrary to shadow3).
"""
import numpy

from syned.beamline.optical_elements.absorbers.absorber import Absorber

from syned.beamline.element_coordinates import ElementCoordinates
from syned.beamline.shape import Rectangle, Ellipse, MultiplePatch

from dabax.dabax_xraylib import DabaxXraylib

from shadow4.physical_models.prerefl.prerefl import PreRefl

from shadow4.beamline.s4_optical_element_decorators import S4OpticalElementDecorator
from shadow4.beamline.s4_beamline_element import S4BeamlineElement
from shadow4.beam.s4_beam import S4Beam

[docs]class S4Screen(Absorber, S4OpticalElementDecorator): def __init__(self, name="Undefined", boundary_shape=None, # for syned absorber i_abs=0, # include absorption: 0=No, 1=using preprocessor file # 2=direct calculation using xraylib # 3=direct calculation using dabax i_stop=0, # aperture/stop thick=0.0, # thickness of the absorber (in SI) file_abs="", # for i_abs=1, the material file (from prerefl) material="", # for i_abs=2,3, the material name density=1.0, # for i_abs=2,3, the material density in g/cm^3 dabax=None, ): """ Constructor. Parameters ---------- name : str, optional The name of the element. boundary_shape : instance of syned Shape, optional The boundary shape. i_abs : int, optional The flag to include absorption: - 0=No, - 1=using preprocessor file, - 2=direct calculation using xraylib, - 3=direct calculation using dabax. i_stop : int, optional Flag to select aperture (0) or stop (1). thick : float, optional The thickness of the filter (for i_abs>0). file_abs : str, optional The file name with material data from the prerefl preprocessor (for i_abs=1). material : str, optional The material identifier: symbol of element or formula (for i_abs>1). density : float, optional The material density (for i_abs>1). dabax : None or instance of DabaxXraylib, The pointer to the dabax library (used for i_abs=3). Returns ------- instance of S4Screen """ super().__init__(name=name, boundary_shape=boundary_shape) self._i_abs = i_abs self._i_stop = i_stop self._thick = thick self._file_abs = file_abs self._material = material self._density = density self._dabax = dabax dabax_txt = "None" if self._i_abs == 3: if isinstance(dabax, DabaxXraylib): dabax_txt = 'DabaxXraylib(file_CrossSec="%s")' % (dabax.get_file_CrossSec()) else: dabax_txt = "DabaxXraylib()" self.__inputs = { "name": name, "boundary_shape": boundary_shape, "i_abs": i_abs, "i_stop": i_stop, "thick": thick , "material": material, "file_abs": file_abs, "density": density, "dabax": dabax_txt, }
[docs] def get_info(self): """ Returns the specific information of the S4 screen optical element. Returns ------- str """ txt = "\n\n" txt += "SCREEN/SLIT/STOP/FILTER\n" if self._i_abs > 1: txt += " Absorber or attenuator" if self._i_abs == 1: txt += " Calculated attenuation from (prerefl) file: %s\n" % self._file_abs elif self._i_abs == 2: txt += " Calculated attenuation using xraylib\n" elif self._i_abs == 3: txt += " Calculated attenuation using dabax\n" boundary = self.get_boundary_shape() try: boundaries = boundary.get_boundaries() txt += "Boundaries are: %s\n" % boundary.__class__.__name__ if self._i_stop == 0: txt += "SLIT or APERTURE\n" else: txt += "STOP or OBSTRUCTION\n" txt += "Boundaries not considered (infinite screen)" txt += " Limits: " + repr( boundaries ) + "\n" txt += boundary.info() except: txt += "Boundaries not considered (infinite screen)" return txt
[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" if 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() else: txt += "\nboundary_shape = None" 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.absorbers.s4_screen import S4Screen optical_element = S4Screen(name='{name:s}', boundary_shape=boundary_shape, i_abs={i_abs:d}, # attenuation: 0=No, 1=prerefl file, 2=xraylib, 3=dabax i_stop={i_stop:d}, # 0=slit or aperture, 1=beam stop thick={thick:g}, # for i_abs>0 file_abs='{file_abs:s}', # for i_abs=1 material='{material:s}', density={density:g}, # for i_abs=2,3 dabax={dabax:s}, # if using dabax (i_abs=3), instance of DabaxXraylib() (use None for default) ) """ txt += txt_pre.format(**self.__inputs) return txt
[docs]class S4ScreenElement(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 S4ScreenElement. """ def __init__(self, optical_element : S4Screen = None, coordinates : ElementCoordinates = None, input_beam : S4Beam = None): super().__init__(optical_element=optical_element if optical_element is not None else S4Screen(), coordinates=coordinates if coordinates is not None else ElementCoordinates(), input_beam=input_beam)
[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) footprint = self.get_input_beam().duplicate() p, q = self.get_coordinates().get_p_and_q() oe = self.get_optical_element() if p != 0.0: footprint.retrace(p, resetY=True) output_beam = footprint.duplicate() apply_crop = True negative = oe._i_stop if apply_crop: shape = oe.get_boundary_shape() if isinstance(shape, Rectangle): x_left, x_right, y_bottom, y_top = shape.get_boundaries() output_beam.crop_rectangle(1, x_left, x_right, 3, y_bottom, y_top, negative=negative, flag_lost_value=flag_lost_value) elif isinstance(shape, Ellipse): a_axis_min, a_axis_max, b_axis_min, b_axis_max = shape.get_boundaries() output_beam.crop_ellipse(1, a_axis_min, a_axis_max, 3, b_axis_min, b_axis_max, negative=negative, flag_lost_value=flag_lost_value) elif isinstance(shape, MultiplePatch): x = output_beam.get_column(1) y = output_beam.get_column(3) INSIDE = numpy.zeros(x.size, numpy.bool_) for i,patch in enumerate(shape.get_patches()): # print(">>> patch: ",patch.info()) inside = patch.check_inside_vector(x, y) INSIDE = numpy.logical_or(INSIDE,inside) flag = output_beam.get_column(10) if negative: flag[numpy.where(INSIDE)] = flag_lost_value else: flag[numpy.where(~INSIDE)] = flag_lost_value output_beam.rays[:, 9] = flag else: pass # reflectivity calculations if oe._i_abs > 0: thickness = oe._thick # the thickness in Filter syned is ignored. TODO: discuss it it could overwrite # thickness = oe._beamline_element_syned._optical_element.get_thickness() energy = output_beam.get_column(26) if oe._i_abs == 1: # prerefl preprocessor file if oe._file_abs != "": try: pr = PreRefl() pr.read_preprocessor_file(oe._file_abs) print(pr.info()) except: raise Exception("Failed to load preprocessor (prerefl) file %s " % oe._file_abs) coeff = pr.get_attenuation_coefficient(energy) elif oe._i_abs == 2: # xraylib coeff = PreRefl.get_attenuation_coefficient_external_xraylib(photon_energy_ev=energy, material=oe._material, density=oe._density) elif oe._i_abs == 3: # dabax coeff = PreRefl.get_attenuation_coefficient_external_dabax(photon_energy_ev=energy, material=oe._material, density=oe._density, dabax=oe._dabax) I_over_I0 = numpy.exp(- coeff * thickness * 1e2) sqrt_I_over_I0 = numpy.sqrt(I_over_I0) output_beam.apply_reflectivities(sqrt_I_over_I0, sqrt_I_over_I0) if q != 0.0: output_beam.retrace(q, resetY=True) return output_beam, footprint
[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 += self.to_python_code_coordinates() txt += "\nfrom shadow4.beamline.optical_elements.absorbers.s4_screen import S4ScreenElement" txt += "\nbeamline_element = S4ScreenElement(optical_element=optical_element, coordinates=coordinates, input_beam=beam)" txt += "\n\nbeam, footprint = beamline_element.trace_beam()" return txt
if __name__ == "__main__": o = S4Screen(dabax=DabaxXraylib()) e = S4ScreenElement() print(e.to_python_code()) print(o.get_info())