# !/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
This module generates Vector_source_XY class for defining sources. Its parent is Vector_field_XY.
The main atributes are:
* x (numpy.array): linear array with equidistant positions. The number of data is preferibly 2**n.
* y (numpy.array): linear array with equidistant positions. The number of data is preferibly 2**n.
* wavelength (float): wavelength of the incident field
* info (str): String with info about the simulation
The magnitude is related to microns: `micron = 1.`
*Class for unidimensional scalar masks*
*Functions*
* plane_wave
* azimuthal_wave
* radial_wave
* gauss_wave
* hermite_gauss_wave
* local_polarized_vector_wave
* local_polarized_vector_wave_radial
* local_polarized_vector_wave_hybrid
"""
from py_pol.jones_vector import Jones_vector
from . import degrees, eps, np, um
from .scalar_fields_XY import Scalar_field_XY
from .scalar_masks_XY import Scalar_mask_XY
from .scalar_sources_XY import Scalar_source_XY
from .vector_fields_XY import Vector_field_XY
[docs]
class Vector_source_XY(Vector_field_XY):
"""Class for vectorial fields.
Parameters:
x (numpy.array): linear array with equidistant positions. The number of data is preferibly 2**n.
y (numpy.array): linear array with equidistant positions. The number of data is preferibly 2**n.
wavelength (float): wavelength of the incident field
info (str): String with info about the simulation
Attributes:
self.x (numpy.array): linear array with equidistant positions. The number of data is preferibly 2**n.
self.y (numpy.array): linear array with equidistant positions. The number of data is preferibly 2**n.
self.wavelength (float): wavelength of the incident field.
self.Ex (numpy.array): Electric_x field
self.Ey (numpy.array): Electric_y field
"""
def __init__(self, x, y, wavelength, info=''):
super().__init__(x, y, wavelength, info)
self.type = 'Vector_source_XY'
[docs]
def constant_polarization(self,
u=1,
v=(1, 0),
has_normalization=False,
radius=0.):
"""Provides a constant polarization to a scalar_source_xy
Parameters:
u (Scalar_source_XY or np.complex): field to apply the polarization or constant value
v (float, float): polarization vector
normalize (bool): If True, normalize polarization vector
"""
if isinstance(radius, (float, int, complex)):
radiusx, radiusy = (radius, radius)
else:
radiusx, radiusy = radius
radius = (radiusx, radiusy)
self = define_initial_field(self, u)
if has_normalization:
v = v / np.linalg.norm(v)
self.Ex = v[0] * self.Ex
self.Ey = v[1] * self.Ey
if radiusx * radiusy > 0:
self.pupil(radius=radius)
[docs]
def azimuthal_wave(self, u=1, r0=(0., 0.), radius=0.):
"""Provides a constant polarization to a scalar_source_xy
Parameters:
u (Scalar_source_XY or np.complex): field to apply the polarization or constant value
r0(float, float): center of rotation
radius (float, float): Radius of a circular mask
"""
if isinstance(radius, (float, int, complex)):
radiusx, radiusy = (radius, radius)
else:
radiusx, radiusy = radius
radius = (radiusx, radiusy)
self = define_initial_field(self, u)
vx = (self.X - r0[0])
vy = (self.Y - r0[1])
angle = np.arctan2(vy, vx)
self.Ex = np.sin(angle) * self.Ex
self.Ey = -np.cos(angle) * self.Ey
if radiusx * radiusy > 0:
self.pupil(r0=r0, radius=radius)
[docs]
def radial_wave(self, u=1, r0=(0., 0.), radius=0.):
"""Provides a constant polarization to a scalar_source_xy
Parameters:
u (Scalar_source_XY or np.complex): field to apply the polarization or constant value
r0(float, float): center of rotation
radius (float, float): Radius of a circular mask
"""
if isinstance(radius, (float, int, complex)):
radiusx, radiusy = (radius, radius)
else:
radiusx, radiusy = radius
radius = (radiusx, radiusy)
self = define_initial_field(self, u)
vx = (self.X - r0[0])
vy = (self.Y - r0[1])
angle = np.arctan2(vy, vx)
self.Ex = np.cos(angle) * self.Ex
self.Ey = np.sin(angle) * self.Ey
if radiusx * radiusy > 0:
self.pupil(r0=r0, radius=radius)
[docs]
def radial_inverse_wave(self, u=1, r0=(0., 0.), radius=0.):
"""Provides a constant polarization to a scalar_source_xy
Parameters:
u (Scalar_source_XY or np.complex): field to apply the polarization or constant value
r0(float, float): center of rotation
radius (float, float): Radius of a circular mask
"""
if isinstance(radius, (float, int, complex)):
radiusx, radiusy = (radius, radius)
else:
radiusx, radiusy = radius
radius = (radiusx, radiusy)
self = define_initial_field(self, u)
vx = (self.X - r0[0])
vy = (self.Y - r0[1])
angle = np.arctan2(vy, vx)
self.Ex = np.cos(angle) * self.Ex
self.Ey = -np.sin(angle) * self.Ey
if radiusx * radiusy > 0:
self.pupil(r0=r0, radius=radius)
[docs]
def azimuthal_inverse_wave(self, u=1, r0=(0., 0.), radius=0.):
"""Provides a constant polarization to a scalar_source_xy
Parameters:
u (Scalar_source_XY or np.complex): field to apply the polarization or constant value
r0(float, float): center of rotation
radius (float, float): Radius of a circular mask
"""
if isinstance(radius, (float, int, complex)):
radiusx, radiusy = (radius, radius)
else:
radiusx, radiusy = radius
radius = (radiusx, radiusy)
self = define_initial_field(self, u)
vx = (self.X - r0[0])
vy = (self.Y - r0[1])
angle = np.arctan2(vy, vx)
self.Ex = np.sin(angle) * self.Ex
self.Ey = np.cos(angle) * self.Ey
if radiusx * radiusy > 0:
self.pupil(r0=r0, radius=radius)
[docs]
def local_polarized_vector_wave(self,
u=1,
r0=(0., 0.),
m=1,
fi0=0,
radius=0.):
""""local radial polarized vector wave.
Parameters:
u (Scalar_source_XY or np.complex): field to apply the polarization or constant value
r0 (float, float): r0 of beam
m (integer): integer with order
fi0 (float): initial phase
radius (float, float): Radius of a circular mask
References:
Qwien Zhan 'Vectorial Optical Fields' page 33
"""
if isinstance(radius, (float, int, complex)):
radiusx, radiusy = (radius, radius)
else:
radiusx, radiusy = radius
radius = (radiusx, radiusy)
self = define_initial_field(self, u)
vx = (self.X - r0[0])
vy = (self.Y - r0[1])
angle = np.arctan2(vy, vx)
delta = m * angle + fi0
self.Ex = self.Ex * np.cos(delta)
self.Ey = self.Ey * np.sin(delta)
if radiusx * radiusy > 0:
self.pupil(r0=r0, radius=radius)
[docs]
def local_polarized_vector_wave_radial(self,
u=1,
r0=(0 * um, 0 * um),
m=1,
fi0=0,
radius=0.):
"""local radial polarized vector wave.
Parameters:
u (Scalar_source_XY or np.complex): field to apply the polarization or constant value
r0 (float, float): center of beam
m (integer): integer with order
fi0 (float): initial phase
radius (float, float): Radius of a circular mask
References:
Qwien Zhan 'Vectorial Optical Fields' page 36
"""
if isinstance(radius, (float, int, complex)):
radiusx, radiusy = (radius, radius)
else:
radiusx, radiusy = radius
radius = (radiusx, radiusy)
if radius == 0:
radius_x = (self.x[-1] - self.x[0]) / 2
radius_y = (self.y[-1] - self.y[0]) / 2
radius = (radius_x, radius_y)
elif isinstance(radius, (float, int, complex)):
radius = (radius, radius)
self = define_initial_field(self, u)
vx = (self.X - r0[0])
vy = (self.Y - r0[1])
r = np.sqrt(vx**2 + vy**2)
radius_0 = min(radius[0], radius[1])
delta = 2 * m * np.pi * r / (radius_0 + eps) + fi0
self.Ex = self.Ex * np.cos(delta)
self.Ey = self.Ey * np.sin(delta)
if radiusx * radiusy > 0:
self.pupil(r0=r0, radius=radius)
[docs]
def local_polarized_vector_wave_hybrid(self,
u=1,
r0=(0 * um, 0 * um),
m=1,
n=1,
fi0=0,
radius=(0, 0)):
"""local hibrid polarized vector wave.
Qwien Zhan 'Vectorial Optial Fields' page 36
Parameters:
u (Scalar_source_XY or np.complex): field to apply the polarization or constant value
r0 (float, float): center of beam
m (integer): integer with order
n (integer): integer with order
fi0 (float): initial phase
radius (float, float): Radius of a circular mask
"""
if isinstance(radius, (float, int, complex)):
radiusx, radiusy = (radius, radius)
else:
radiusx, radiusy = radius
radius = (radiusx, radiusy)
if radiusx * radiusy == 0:
radius_x = (self.x[-1] - self.x[0]) / 2
radius_y = (self.y[-1] - self.y[0]) / 2
radius = (radius_x, radius_y)
elif isinstance(radius, (float, int, complex)):
radius = (radius, radius)
self = define_initial_field(self, u)
vx = (self.X - r0[0])
vy = (self.Y - r0[1])
angle = np.arctan2(vy, vx)
r = np.sqrt(vx**2 + vy**2)
radius_0 = min(radius[0], radius[1])
delta = m * angle + 2 * n * np.pi * r / (radius_0 + eps) + fi0
self.Ex = self.Ex * np.cos(delta)
self.Ey = self.Ey * np.sin(delta)
if radiusx * radiusy > 0:
self.pupil(r0=r0, radius=radius)
[docs]
def spiral_polarized_beam(self,
u=1,
r0=(0 * um, 0 * um),
alpha=0,
radius=(0, 0)):
"""Define spiral polarized beams:
Parameters:
u (Scalar_source_XY or np.complex): field to apply the polarization or constant value
r0 (float, float): center of radiality
radius (float): mask for circle if radius >0.
alpha (float): angle of spiral.
Reference:
V. Ramirez-Sanchez, G. Piquero, and M. Santarsiero,“Generation and characterization of spirally polarized fields,” J. Opt. A11,085708 (2009)
"""
if isinstance(radius, (float, int, complex)):
radiusx, radiusy = (radius, radius)
else:
radiusx, radiusy = radius
radius = (radiusx, radiusy)
self = define_initial_field(self, u)
vx = (self.X - r0[0])
vy = (self.Y - r0[1])
theta = np.arctan2(vy, vx)
self.Ex = -self.Ex * np.sin(theta + alpha)
self.Ey = self.Ey * np.cos(theta + alpha)
if radiusx * radiusy > 0:
self.pupil(r0=r0, radius=radius)
[docs]
def to_py_pol(self):
"""Pass Ex, Ey field to py_pol package for software analysis
"""
j0 = Jones_vector(name="from Diffractio")
j0.from_components(Ex=self.Ex, Ey=self.Ey)
return j0
[docs]
def define_initial_field(EM, u=None):
"""Defines the initial field EM = (Ex, Ey) in terms of u.
Parameters:
EM (vector_source_XY):
u (scalar_source_XY, or None, or 1): if scalar_source it is written in Ex and Ey, is 1 Ex=1, Ey=1, if None, does nothing,
"""
# check data size
if isinstance(u, (float, int, complex)):
EM.Ex = u * np.ones_like(EM.Ex)
EM.Ey = u * np.ones_like(EM.Ey)
elif isinstance(u, (Scalar_mask_XY, Scalar_field_XY, Scalar_source_XY)):
EM.Ex = u.u
EM.Ey = u.u
if u in (0, None, '', []):
EM.Ex = np.ones_like(EM.Ex)
EM.Ey = np.ones_like(EM.Ey)
return EM