"""
WOMirror1D — wofry 1-D mirror with conic-surface height profile and Huygens-integral propagation.
"""
import numpy
from syned.beamline.optical_elements.mirrors.mirror import Mirror
#
from wofry.beamline.decorators import OpticalElementDecorator
from wofryimpl.beamline.optical_elements.util.s4_conic import S4Conic # copied from shadow4 -
from wofry.propagator.wavefront1D.generic_wavefront import GenericWavefront1D
from numba import jit, prange
[docs]
@jit(nopython=True, parallel=True)
def goFromToSequential(field1, x1, y1, x2, y2, wavelength=1e-10, normalize_intensities=False):
field2 = x2 * 0j
wavenumber = numpy.pi * 2 / wavelength
for i in prange(field2.size):
r = numpy.sqrt(numpy.power(x1 - x2[i], 2) + numpy.power(y1 - y2[i], 2))
field2[i] = (field1 * numpy.exp(1.j * wavenumber * r)).sum()
if normalize_intensities:
field2 *= numpy.sqrt((numpy.abs(field1) ** 2).sum() / (numpy.abs(field2) ** 2).sum())
return field2
[docs]
class WOMirror1D(Mirror, OpticalElementDecorator):
def __init__(self,
name="Undefined",
surface_shape=None,
boundary_shape=None,
coating=None,
coating_thickness=None,
keywords_at_creation=None):
Mirror.__init__(self, name=name,
surface_shape=surface_shape,
boundary_shape=boundary_shape,
coating=coating, coating_thickness=coating_thickness)
self._keywords_at_creation = keywords_at_creation
[docs]
def get_height_profile(self, input_wavefront):
shape = self._keywords_at_creation["shape"]
p_focus = self._keywords_at_creation["p_focus"]
q_focus = self._keywords_at_creation["q_focus"]
grazing_angle_in = self._keywords_at_creation["grazing_angle_in"]
error_flag = self._keywords_at_creation["error_flag"]
error_file = self._keywords_at_creation["error_file"]
error_file_oversampling_factor = self._keywords_at_creation["error_file_oversampling_factor"]
mirror_length = self._keywords_at_creation["mirror_length"]
mirror_points = self._keywords_at_creation["mirror_points"]
if error_flag == 0: # no profile file
x2_oe = numpy.linspace(-0.5 * mirror_length, 0.5 * mirror_length,
mirror_points) # x1 / numpy.sin(grazing_angle_in)
y2_oe = numpy.zeros_like(x2_oe)
else:
a = numpy.loadtxt(error_file)
x2_oe = a[:, 0]
y2_oe = a[:, 1]
if error_file_oversampling_factor != 1:
xnew = numpy.linspace(x2_oe[0], x2_oe[-1], int(x2_oe.size * error_file_oversampling_factor))
ynew = numpy.interp(xnew, x2_oe, y2_oe)
x2_oe = xnew
y2_oe = ynew
if shape == 0:
height = numpy.zeros_like(x2_oe)
elif shape == 1:
ccc = S4Conic.initialize_as_sphere_from_focal_distances(p_focus, q_focus, grazing_angle_in)
height = ccc.height(x2_oe)
y2_oe += height
elif shape == 2:
ccc = S4Conic.initialize_as_ellipsoid_from_focal_distances(p_focus, q_focus, grazing_angle_in)
height = ccc.height(x2_oe)
y2_oe += height
elif shape == 3:
ccc = S4Conic.initialize_as_paraboloid_from_focal_distances(p_focus, q_focus, grazing_angle_in)
height = ccc.height(x2_oe)
y2_oe += height
else:
raise Exception("Wrong shape")
return x2_oe, y2_oe
[docs]
def applyOpticalElement(self, input_wavefront, parameters=None, element_index=None):
grazing_angle_in = self._keywords_at_creation["grazing_angle_in"]
flip = self._keywords_at_creation["flip"]
p_distance = self._keywords_at_creation["p_distance"]
q_distance = self._keywords_at_creation["q_distance"]
zoom_factor = self._keywords_at_creation["zoom_factor"]
write_profile = self._keywords_at_creation["write_profile"]
x2_oe, y2_oe = self.get_height_profile(input_wavefront)
output_wavefront, x2_oe, y2_oe, field2 = self.propagator1D_offaxis(input_wavefront, x2_oe, y2_oe,
p_distance, q_distance,
grazing_angle_in,
zoom_factor=zoom_factor,
normalize_intensities=True,
flip=flip)
# output files
if write_profile:
f = open("reflector_profile1D.dat", "w")
for i in range(x2_oe.size):
f.write("%g %g\n" % (x2_oe[i], y2_oe[i]))
f.close()
if self._keywords_at_creation["verbose"]: print("File reflector_profile1D.dat written to disk.")
return output_wavefront
[docs]
@classmethod
def propagator1D_offaxis(cls, input_wavefront, x2_oe, y2_oe, p, q, theta_grazing_in, theta_grazing_out=None,
zoom_factor=1.0, normalize_intensities=False, flip=0):
if theta_grazing_out is None:
theta_grazing_out = theta_grazing_in
x1 = input_wavefront.get_abscissas()
field1 = input_wavefront.get_complex_amplitude()
wavelength = input_wavefront.get_wavelength()
if flip == 0:
x1_oe = -p * numpy.cos(theta_grazing_in) + x1 * numpy.sin(theta_grazing_in)
y1_oe = p * numpy.sin(theta_grazing_in) + x1 * numpy.cos(theta_grazing_in)
else:
x1_oe = p * numpy.cos(theta_grazing_in) + x1 * numpy.sin(theta_grazing_in)
y1_oe = p * numpy.sin(theta_grazing_in) - x1 * numpy.cos(theta_grazing_in)
# field2 is the electric field in the mirror
field2 = goFromToSequential(field1, x1_oe, y1_oe, x2_oe, y2_oe,
wavelength=wavelength, normalize_intensities=normalize_intensities)
x3 = x1 * zoom_factor
if flip == 0:
x3_oe = q * numpy.cos(theta_grazing_out) - x3 * numpy.sin(theta_grazing_out)
y3_oe = q * numpy.sin(theta_grazing_out) + x3 * numpy.cos(theta_grazing_out)
else:
x3_oe = -q * numpy.cos(theta_grazing_out) - x3 * numpy.sin(theta_grazing_out)
y3_oe = q * numpy.sin(theta_grazing_out) - x3 * numpy.cos(theta_grazing_out)
# field3 is the electric field in the image plane
field3 = goFromToSequential(field2, x2_oe, y2_oe, x3_oe, y3_oe,
wavelength=wavelength, normalize_intensities=normalize_intensities)
output_wavefront = GenericWavefront1D.initialize_wavefront_from_arrays(x3, field3 / numpy.sqrt(zoom_factor),
wavelength=wavelength)
return output_wavefront, x2_oe, y2_oe, field2
[docs]
@classmethod
def propagator1D_offaxis_up_to_mirror(cls, input_wavefront, x2_oe, y2_oe, p, theta_grazing_in,
normalize_intensities=False):
x1 = input_wavefront.get_abscissas()
field1 = input_wavefront.get_complex_amplitude()
wavelength = input_wavefront.get_wavelength()
x1_oe = -p * numpy.cos(theta_grazing_in) + x1 * numpy.sin(theta_grazing_in)
y1_oe = p * numpy.sin(theta_grazing_in) + x1 * numpy.cos(theta_grazing_in)
# field2 is the electric field in the mirror
field2 = goFromToSequential(field1, x1_oe, y1_oe, x2_oe, y2_oe,
wavelength=wavelength, normalize_intensities=normalize_intensities)
return field2
[docs]
@classmethod
def create_from_keywords(cls,
name="mirror 1D",
shape=0,
flip=0,
p_focus=1.0,
q_focus=1.0,
grazing_angle_in=0.003,
p_distance=1.0,
q_distance=1.0,
zoom_factor=1.0,
error_flag=0,
error_file="",
error_file_oversampling_factor=1.0,
mirror_length=1.0,
mirror_points=100,
write_profile=0,
verbose=1,
):
keywords_at_creation = {}
keywords_at_creation["name"] = name
keywords_at_creation["shape"] = shape
keywords_at_creation["flip"] = flip
keywords_at_creation["p_focus"] = p_focus
keywords_at_creation["q_focus"] = q_focus
keywords_at_creation["grazing_angle_in"] = grazing_angle_in
keywords_at_creation["p_distance"] = p_distance
keywords_at_creation["q_distance"] = q_distance
keywords_at_creation["zoom_factor"] = zoom_factor
keywords_at_creation["error_flag"] = error_flag
keywords_at_creation["error_file"] = error_file
keywords_at_creation["error_file_oversampling_factor"] = error_file_oversampling_factor
keywords_at_creation["mirror_length"] = mirror_length
keywords_at_creation["mirror_points"] = mirror_points
keywords_at_creation["write_profile"] = write_profile
keywords_at_creation["verbose"] = verbose
out = WOMirror1D(name="Undefined",
surface_shape=None,
boundary_shape=None,
coating=None,
coating_thickness=None,
keywords_at_creation=keywords_at_creation)
# out._keywords_at_creation = keywords_at_creation
return out
[docs]
def to_python_code(self, do_plot=False):
if self._keywords_at_creation is None:
raise Exception("Python code autogenerated only if created with WOLens.create_from_keywords()")
txt = "\n"
txt += "\nfrom wofryimpl.beamline.optical_elements.mirrors.mirror import WOMirror1D"
txt += "\n"
txt += "\noptical_element = WOMirror1D.create_from_keywords("
txt += "\n name='%s'," % self._keywords_at_creation["name"]
txt += "\n shape=%d," % self._keywords_at_creation["shape"]
txt += "\n flip=%d," % self._keywords_at_creation["flip"]
txt += "\n p_focus=%g," % self._keywords_at_creation["p_focus"]
txt += "\n q_focus=%g," % self._keywords_at_creation["q_focus"]
txt += "\n grazing_angle_in=%g," % self._keywords_at_creation["grazing_angle_in"]
txt += "\n p_distance=%g," % self._keywords_at_creation["p_distance"]
txt += "\n q_distance=%g," % self._keywords_at_creation["q_distance"]
txt += "\n zoom_factor=%g," % self._keywords_at_creation["zoom_factor"]
txt += "\n error_flag=%d," % self._keywords_at_creation["error_flag"]
txt += "\n error_file='%s'," % self._keywords_at_creation["error_file"]
txt += "\n error_file_oversampling_factor=%g," % self._keywords_at_creation["error_file_oversampling_factor"]
txt += "\n mirror_length=%g," % self._keywords_at_creation["mirror_length"]
txt += "\n mirror_points=%d," % self._keywords_at_creation["mirror_points"]
txt += "\n write_profile=%d," % self._keywords_at_creation["write_profile"]
txt += "\n verbose=%d)" % self._keywords_at_creation["verbose"]
txt += "\n"
return txt
#
#
#
if __name__ == "__main__":
womirror = WOMirror1D.create_from_keywords(write_profile=1, verbose=0)
print(womirror.info())
print(womirror.to_python_code())
for key in womirror._keywords_at_creation.keys():
print(key, womirror._keywords_at_creation[key])
from wofry.propagator.wavefront1D.generic_wavefront import GenericWavefront1D
input_wavefront = GenericWavefront1D.initialize_wavefront_from_range(x_min=-0.0005, x_max=0.0005,
number_of_points=1000)
input_wavefront.set_photon_energy(10000)
input_wavefront.set_spherical_wave(radius=13.73, center=0, complex_amplitude=complex(1, 0))
output_wavefront = womirror.applyOpticalElement(input_wavefront=input_wavefront)
from srxraylib.plot.gol import plot
plot(input_wavefront.get_abscissas(), input_wavefront.get_intensity())
plot(output_wavefront.get_abscissas(),output_wavefront.get_intensity())