Welcome to dtmm’s documentation!¶
Overview¶
dtmm
is a free and open-source software package for near-field propagation and visualization of electro-magnetic fields in complex birefringent media. Useful for calculation of:
Transmittance & reflectance of thin structures, e.g., confined liquid crystals.
Polarizing optical microscope simulation. See Example.
DTMM stands for Diffractive Transfer Matrix Method and is an adapted Berreman 4x4 transfer matrix method and an adapted 2x2 extended Jones method. Details of the method are given in … some future paper. See The Method for a quick explanation of the method.
See also
If you are into transmission optical microscopy simulations you may want to check nemaktis, which uses dtmm
as one of the back-ends.
License¶
dtmm
is released under MIT license so you can use it freely. Please cite the package if you use it to prepare plots for scientific paper. See the DOI badge in the repository
Contributors¶
I thank the following people for contributing and for valuable discussions:
Alex Vasile
Guilhem Poy
Highlights¶
Easy-to-use interface.
Fast and efficient code.
Support for the nematic director, Q tensor or dielectric tensor input data.
Computes transmission and reflection from the material.
Computes interference and diffraction effects.
Biaxial, uniaxial and isotropic material supported.
Support for dispersive material: Cauchy or Sellmeier data.
Fast iterative algorithm for 3D data - with tunable accuracy.
Non-iterative algorithm for 2D data - equivalent to the iterative algorithm with max accuracy settings.
Exact calculation for homogeneous layers (1D).
EM field visualizer (polarizing microscope simulator) allows you to simulate:
Light source intensity.
Polarizer/analyzer orientation and type (LCP, RCP or linear).
Phase retarders (lambda/4, lambda/2).
Sample rotation.
Focal plane adjustments.
Koehler illumination (field aperture).
Objective aperture.
Immersion or standard microscopes.
Cover glass aberration effects.
Color rendering (RGB camera simulations based on CIE color matching functions).
Pre-defined spectral response for monochrome CMOS cameras.
Status and limitations¶
dtmm
was developed mainly for light propagation through liquid crystals, but it can also be used for simple 1D simulations using Jones calculus, or transfer matrix method. See the tutorial section for details. There are still some unresolved issues and limitations. These limitations are likely to be improved/implemented in the future (Contributions are welcome):
Limited color rendering functions and settings - no white balance correction of computed images.
Regular-spaced mesh only with equal spacing in x and y directions.
Note
EM field propagation calculation based on the iterative and non-iterative approach for 2D and 3D is exact for homogeneous layers, but it is approximate for inhomogeneous layers. See Accuracy and efficiency for details.
The package is still evolving, so there may be some small API changes in the future. Other than that, the package is fully operational. Play with the example below to get an impression on how it works.
Example¶
>>> import dtmm
>>> import numpy as np
>>> NLAYERS, HEIGHT, WIDTH = (60, 96, 96)
>>> WAVELENGTHS = np.linspace(380,780,9)
Build a sample optical data; a nematic droplet with a hedgehog defect in the center:
>>> optical_block = dtmm.nematic_droplet_data((NLAYERS, HEIGHT, WIDTH),
... radius = 30, profile = "r", no = 1.5, ne = 1.6, nhost = 1.5)
Build illumination data (input EM field); a multi-wavelength plane wave source:
>>> field_data_in = dtmm.illumination_data((HEIGHT, WIDTH), WAVELENGTHS,
... pixelsize = 200)
Transfer the field through the sample:
>>> field_data_out = dtmm.transfer_field(field_data_in, [optical_block])
Visualize the transmitted field with matplotlib plot:
>>> viewer = dtmm.pom_viewer(field_data_out)
>>> viewer.set_parameters(sample = 0, polarizer = "h",
... focus = -18, analyzer = "v")
>>> fig, ax = viewer.plot() #creates matplotlib figure and axes
>>> fig.show()

Simulated optical polarizing microscope image of a nematic droplet with a radial nematic director profile (a point defect in the middle of the sphere). You can use sliders to change the focal plane, polarizer, sample rotation, analyzer, and light intensity. (Source code, png, hires.png, pdf)¶
Curious enough? Read the Quickstart Guide.
Contact¶
Andrej {dot} Petelin {at} gmail {dot} com
Installation¶
The code is hosted on GitHub. You can install latest stable release with:
$ pip install dtmm
Or you can clone or download the latest development code from the repository and run:
$ python setup.py install
which should install the package, provided that all requirements are met.
Requirements¶
Prior to installing, you should have a working python 3.x environment consisting of:
numba >= 0.45.0
numpy >= 1.20
For matplotlib-based GUI:
scipy
matplotlib
To install these, it is best to go with one of the python distributions, e.g. anaconda, or any other python distribution that is shipped with the above packages.
For faster FFT calculation, you should also install mkl_fft that is readily available in anaconda. If mkl_fft is not available in your system, you can also try installing pyfftw. See the Configuration & Tips for details.
Installing in Anaconda¶
Open the terminal (command prompt) and run:
$ conda install numba scipy matplotlib numba
$ pip install dtmm
Optionally, for faster FFT computation, you can install mkl_fft:
$ conda install mkl_fft
The Method¶
dtmm
implements a few different algorithms/implementations. The choice of the method used depends on the dimensionality of the system. For 3D, there is an iterative algorithm beam propagation implementation, and for 2D and 1D data you can use the non-iterative algorithm, a 4x4 or 2x2 transfer-matrix-based formulation.
Non-iterative 1D & 2D¶
For 1D simulations, the package provides the standard 4x4 transfer matrix method and the 2x2 extended Jones method. For the 4x4 approach, please refer to the literature on the 4x4 transfer matrix approach, or Berreman calculus. The 2x2 approach was implemented as a backend for the 3D simulations and is a scattering matrix formulation done with E-field only (no H field). Therefore, it handles transmission only. For reflection calculations you must use the 4x4 approach.
For 2D simulations the package also provides the 2D transfer matrix formalism, so you can build the NxNx4x4 (or NxNx2x2) transfer matrices for the N propagating modes. This is computationally expensive, but it is manageable in 2D. With this approach you can compute the reflections from reflection gratings, for instance.
The same concept is available for 3D, but here it is impractical to use the transfer matrix approach, except when dimensions are small or for very high-reflecting data and you are advised to use the iterative algorithm developed for 3D data, as explained below.
Iterative 3D¶
For 3D simulations, a vectorial split-step beam propagation method is used. The algorithm splits the material into layers and performs propagation through the layers layer-by-layer in a split-step fashion. Each layer is treated as a combination of a first thin birefringent film, a homogeneous thick medium, and a second thin birefringent film. The two thin layers are there to simulate the phase difference that the input wave acquires as it passes or reflects from the layer because of the birefringence of the material. The homogeneous thick layer simulates the phase shift that the waves acquire as they travel through the layer, and therefore captures the diffraction properties of the light propagation. The algorithm computes Fresnel reflection coefficients at the interfaces, which allows one to track the reflected waves. The phase shift and reflection/transmission coefficients are calculated using Berreman 4x4 calculus (or the extended Jones formalism - user selectable). The diffraction propagation step is done in Fourier space; the field is Fourier transformed and propagated forward or backward (depending if we treat transmitted waves or reflected waves) through the layer thickness. To calculate reflected fields, multiple passes of the input field are performed. User provides the number of passes.
The algorithm allows one to tune the diffraction/reflection calculation accuracy. In the simplified scheme, the input field is treated as a single beam with a well-defined propagation direction. This scheme is good for thin material, where the diffraction effects are small. In a more advanced (and more accurate) scheme, the propagation/reflection is done using the mode-grouping technique. After each pass through the layer, the algorithm performs mode decomposition. Then, it combines the computed modes into a user-defined number of beams with different wave vector orientations by a grouping of modes. In other words, the EM field is assumed to be a sum of n beams, where n is the user-defined parameter. In samples that induce high-frequency reflection/transmission modes, this approach improves the calculation of reflection coefficients and accurately diffracts high-frequency modes, which is important for thick cells.
Accuracy and efficiency¶
The algorithm converges to the exact solution in samples with homogeneous layers, and is a reasonable approximation when used in samples with inhomogeneous layers if the lateral (within the layer) variations of the dielectric tensor are slow (compared to the wavelength) and if the birefringence is weak. In thin disordered systems with rapidly varying dielectric tensor, the algorithm also works reasonably well, because the light “sees” only the mean refractive index, and the diffraction effects become less important. The algorithm fails in sub-wavelength periodic structures, metamaterials …
The iterative approach is very efficient, especially for transmittance/reflectance calculations in weakly reflecting systems. For instance, the algorithm can be more than 100x faster than an equivalent calculation done with FDTD algorithm. Although the code is written in python, the code’s computationally expensive parts are optimized by numba, and it can run in parallel on multi-core CPUs.
Reflection calculation speed and accuracy depends on the required number of light passes, so it can become slower to compute in system with high reflectance. Also, for highly reflecting samples (eg. cholesteric reflection mirror with reflectance >> 50%) the algorithm may not converge, but the algorithm allows you to determine whether it has converged or not.
Quickstart Guide¶
Here you will learn how to construct optical data with the provided helper functions and how to perform calculations for the most typical use case that this package was designed for - propagation of light through a liquid-crystal cell with inhomogeneous director configuration, and visualization (simulation of the optical polarizing microscope imaging). If you are curious about the implementation details you are also advised to read the Data Model first and then go through the examples below. More detailed examples and tutorials are given in the Tutorial.
First, import the library and, optionally, set the verbose level so that you can see the progress and information about the computation.
>>> import dtmm
>>> dtmm.conf.set_verbose(2) # 0 (no info), 1 (some info) or 2 (max info)
0
>>> dtmm.conf.set_verbose(0) # disable for doctests below.
2
Importing director data¶
Say you have a director data stored in a raw or text file (or create a sample director data to work with).
>>> NLAYERS, HEIGHT, WIDTH = (60, 96, 96)
>>> director = dtmm.nematic_droplet_director((NLAYERS, HEIGHT, WIDTH), radius = 30, profile = "r")
>>> director.tofile("director.raw")
Here we have generated a director data array and saved it to a binary file written in system endianness called “director.raw”. The data stored in this file is of shape (60,96,96,3), that is (NLAYERS, HEIGHT, WIDTH, 3). That is, a director as a vector defined in each voxel of the computation box. The length of the director vector is either 1, where the director is inside the sphere, and 0 elsewhere. To load this data from file you can use the dtmm.read_director()
helper function:
>>> director = dtmm.read_director("director.raw", (NLAYERS, HEIGHT, WIDTH ,3))
By default, data is assumed to be stored in double precision and with “zyxn” data order and system endianness. If you have data in single precision and different order, these have to be specified. For instance, if data is in “xyzn” order, meaning that first axis is “x”, and third axis is “z” coordinate (layer index) and the last axis is the director vector, and the data is in single precision little endianness, do:
>>> director = dtmm.read_director("test.raw", (WIDTH,HEIGHT,NLAYERS,3),
... order = "xyzn", dtype = "float32", endian = "little")
This reads director data and transposes it from (WIDTH, HEIGHT, NLAYERS,3) to shape (NLAYERS, HEIGHT, WIDTH, 3), a data format that is used internally for computation. Now we can build the optical data from the director array by providing the refractive indices of the liquid crystal material.
>>> optical_block = dtmm.director2data(director, no = 1.5, ne = 1.6)
This converts director to a valid optical block data. Director array should be an array of director vectors. Length of the vector should generally be 1. Director length is used to determine the dielectric tensor of the material. See Optical Data for details. You can also set the director mask. For instance, a sphere mask of radius 30 pixels can be defined by
>>> mask = dtmm.sphere_mask((NLAYERS,HEIGHT,WIDTH),30)
With this mask you can construct optical data of a nematic droplet in a host material with refractive index of 1.5:
>>> optical_block = dtmm.director2data(director, no = 1.5, ne = 1.6, mask = mask, nhost = 1.5)
Of course you can provide any mask, just that the shape of the mask must mach the shape of the bounding box of the director - (60,96,96) in our case. This way you can crop the director field to any volume shape and put it in a host material with the above helper function.
Note
For testing, there is a dtmm.nematic_droplet_data()
function that you can call to construct a test data of nematic droplet data directly. See Optical Data for details.
Sometimes you will need to expand the computation box (increase the volume). You can do that with
>>> director_large = dtmm.expand(director, (60,128,128))
This grows the computation box in lateral dimensions symmetrically, by filling the missing data points with zeros. For a more complex data creation please refer to the Optical Data format.
Note
By expansion in lateral dimension we provide more space between the borders and the feature that we wish to observe. This way we can reduce border effects due to the periodic boundary conditions implied by the Fourier transform that is used in diffraction calculation.
Importing Q tensor data¶
If you want to work with Q tensor data described by a matrix (NLAYERS, HEIGHT, WIDTH ,6), where the 6 components of the tensor are (Qxx, Qyy, Qzz, Qxy, Qxz, Qyz), there are some conversion functions to use:
>>> Q = dtmm.data.director2Q(director)
>>> Q.tofile("Qtensor.raw")
>>> Q = dtmm.data.read_tensor("Qtensor.raw", (NLAYERS, HEIGHT, WIDTH ,6))
You can convert the tensor to director. This assumes, that you have uniaxial symmetry. If the Q tensor is not uniaxial, the conversion function first makes it uniaxial, by finding the eigenvalues and eigenvectors and determining the most distinctive eigenvalue to determine the orientation of the main axis of the tensor.
>>> director = dtmm.data.Q2director(Q)
Alternative approach is to build the epsilon tensor from the Q tensor like
>>> eps = dtmm.data.Q2eps(Q, no = 1.5, ne = 1.6, scale_factor = 1.)
Here the scale_factor argument defines the scaling of the effective uniaxial order parameter S. The above function performs where s is the scale factor. The mean value is set to
. Then dielectric tensor is computed from the diagonal and off-diagonal elements of Q as
.
Next, we need to convert the epsilon tensor to eigenvalue and Euler angles matrices with
>>> epsv, epsa = dtmm.data.eps2epsva(eps)
Alternatively, you can use the convenience function to convert Q tensor to optical_block directly
>>> optical_block = dtmm.data.Q2data(Q,no = 1.5, ne = 1.6, scale_factor = 1.)
Note
By default, the data.Q2data()
converts the tensor to an uniaxial. There are very few use cases where biaxial order plays an important role in optical imaging. Also, the algorithm is much more efficient for uniaxial material, so you are advised to convert the tensor to uniaxial even if your sample is (weakly) biaxial.
Transmission Calculation¶
In this part we will cover transmission calculation and light creation functions for simulating optical polarizing microscope images. First we will create and compute the transmission of a single plane wave and then show how to compute multiple rays (multiple plane waves with different ray directions) in order to simulate finite numerical aperture of the illuminating light field.
Plane wave illumination (single ray)¶
Now that we have defined the sample data we need to construct initial (input) electro-magnetic field. Electro magnetic field is defined by an array of shape (4,height,width) where the first axis defines the component of the field, that is, an ,
,
and
components of the EM field specified at each of the (y,x) coordinates. To calculate transmission spectra, multiple wavelengths need to be simulated. A multi-wavelength field has a shape of (n_wavelengths,4,height,width). You can define a multi-wavelength input light electro-magnetic field data with a
dtmm.illumination_data()
helper function.
>>> import numpy as np
>>> WAVELENGTHS = np.linspace(380,780,11)
>>> field_data = dtmm.illumination_data((HEIGHT,WIDTH), WAVELENGTHS, pixelsize = 200, jones = (1,0))
Here we have defined an x-polarized light (we used jones vector of (1,0)). A left-handed circular polarized light can be defined by:
>>> jones = (1/2**0.5,1j/2**0.5)
or equivalently:
>>> jones = dtmm.jonesvec((1,1j)) #performs automatic normalization of the jones vector
>>> field_data_in = dtmm.illumination_data((HEIGHT,WIDTH), WAVELENGTHS, pixelsize = 200, jones = jones)
Warning
The illumination_data function expects the jones vector to be normalized, as it is directly multiplied with EM field coefficients. If this vector is not normalized, intensity of the illumination data changes accordingly.
Most times you need the input light to be non-polarized. A non-polarized light is taken to be a combination of x and y polarizations that are transmitted independently and the resulting intensity measured by the detector is an incoherent addition of both of the contributions from both of the two polarizations. So to simulate a non-polarized light, you have to compute both of the polarization states. The illumination_data function can be used to construct such data. Just specify jones parameter to None or call the function without the jones parameter:
>>> field_data_in = dtmm.illumination_data((HEIGHT,WIDTH), WAVELENGTHS, pixelsize = 200, n = 1.5)
In the field data above we have also used n = 1.5 argument, which defines a forward propagating wave in a medium with refractive index of 1.5. This way we can match the effective refractive index of the optical stack to eliminate reflection from the first surface. With the input light specified, you can now transfer this field through the stack. Optical data is a list of optical blocks.
>>> optical_data = [optical_block]
>>> field_data_out = dtmm.transfer_field(field_data_in, optical_data, nin = 1.5, nout = 1.5)
Here we have set the index matching medium by specifying nin and nout arguments to the effective refractive index of the medium. By default input and output fields are assumed to be propagating in n_cover medium, 1.5 by default.
Note
The transfer_field function by default uses 2x2 method and does not compute reflections. Therefore, nin and nout arguments must be equal. If they are not, you must enable reflections. See Tutorial for details on reflections and interference.
Koehler illumination (multiple rays)¶
If you want to simulate Koehler illumination (see koehler for a nice description of the model) with finite numerical aperture (condenser aperture) multiple rays (or multiple plane waves) needs to be simulated. Directions of these rays have to be defined. A simple approach is to use the illumination_rays helper function. This function returns beta values and phi values of the input rays for a specified numerical aperture of the illumination.
Note
Beta is a sine of ray angle towards the z axis. See Data Model for details.
For numerical aperture of NA = 0.1 you can call
>>> beta, phi, intensity = dtmm.illumination_rays(0.1,7, smooth = 0.2)
which constructs direction parameters and intensity (beta, phi, intensity) of input rays of numerical aperture of 0.1 and with approximate number of rays of Pi*3.5*3.5. It defines a cone of light rays, where each ray originates from a different evenly distributed angle determined from the position of the pixel in a diaphragm of a diameter specified by the second parameter (e.g. 7). Therefore in our case
>>> len(beta)
37
we have 37 rays evenly distributed in a cone of numerical aperture of 0.1.

The beta and beta values of the 37 ray parameters. The color represents the intensity of the ray. (Source code, png, hires.png, pdf)¶
To calculate the transmitted field we now have to pass these ray parameters to the illumination_data and transfer_field functions:
>>> field_data_in = dtmm.illumination_data((HEIGHT,WIDTH), WAVELENGTHS, pixelsize = 200, beta = beta, phi = phi, intensity = intensity, n = 1.5)
>>> field_data_out = dtmm.transfer_field(field_data_in, optical_data, beta = beta, phi = phi, nin = 1.5, nout = 1.5)
Note that we have passed the beta and phi arguments to the transfer_field function, which tells the algorithm that input data is to be treated as multi-ray data and to use the provided values for the ray incidence direction, which is used to determine the reflection/trasnmission properties over the layers. These parameters must match the beta and phi values used in field source creation. Optionally, you can leave the dtmm determine the correct beta and phi, by omitting these parameters and specifying the multiray argument like:
>>> field_data_out = dtmm.transfer_field(field_data_in, optical_data, multiray = True)
Be aware that by default, the illumination_data function creates eigenfields, except if you pass an optional window parameter. Therefore, by default, the beta and phi parameters are approximate values of the true wave vector orientation. See field.illumination_data()
for details. Consequently, in reflection calculations in particular, you may face inaccurate calculations resulting from the ill-defined beta values at oblique incidence and at high numerical apertures (the betamax parameter). For an accurate multi-wavelength calculation at oblique incidence use
>>> field_data_out = dtmm.transfer_field(field_data_in, optical_data, multiray = True, split_wavelengths = True)
which treats data at each wavelength as independent, and determines the true incidence angle from the data at each wavelength separately, as opposed to calculating the mean k-vector incidence angle when setting split_wavelengths = False.
Warning
When doing multiple ray computation, the beta and phi parameters in the tranfer_field function must match the beta and phi parameters that were used to generate input field. Do not forget to pass the beta, phi values, or do not forget to specify multiray = True. You are also advised to split the calculation with multi_wavelength argument, for more accurate results.
The dtmm.transfer_field()
also takes several optional parameters. One worth mentioning at this stage is the split_rays parameter. If you have large data sets in multi-ray computation, memory requirements for the computation and temporary files may result in out-of-memory issues. To reduce temporary memory storage you can set the split_rays parameter to True. This way you can limit memory consumption (with large number of rays) more or less to the input field data and output field data memory requirements. So for large multi-ray computations do:
>>> filed_out = dtmm.transfer_field(field_data_in, optical_data, multiray = True, split_rays = True)
Note
You can also perform calculations in single precision to further reduce memory consumption (and increase computation speed). See the Configuration & Tips for details.
Microscope simulation¶
After the transmitted field has been calculated, we can simulate the optical polarizing microscope image formation with the POMViewer object. The output field is a calculated EM field at the exit surface of the optical stack. As such, it can be further propagated, and optical polarizing microscope image formation can be performed. Instead of doing full optical image formation calculation, one can take the computed field and propagate it in space (forward or backward) from the initial position. This way, one can calculate light intensities that would have been measured by a camera-equipped microscope had the field been propagated through an ideal microscope objective with 1:1 magnifications. Simply do:
>>> viewer = dtmm.pom_viewer(field_data_out, n_cover = 1.5, d_cover = 0., NA = 0.7, immersion = False)
which returns a POMViewer object for simulating standard objective (non-immersion type) with NA of 0.7. Here we have used the thickness of the cover glass d_cover = 0. This tells the algorithm to neglect the diffraction effects introduced by the thick cover glass. If you have a thick cover glass in the experiment, and you have simulated the field using the transfer_field function with nout = n_cover at the exit surface of the sample, you can use the d_cover argument to simulate aberration effects introduced by the thick cover glass.
Note
For immersion objectives you should specify immersion = True. Here you can use higher NA values. With argument n (defaults to n_cover for immersion objectives) you can specify the refractive index of the output medium (immersion or air).
Warning
You should always match the n_cover argument to that what was used as an output nout refractive index (or input refractive index nin in case you investigate reflections).
Now you can calculate transmission specter or obtain RGB image. Depending on how the illumination data was created (polarized/nonpolarized light, single/multiple ray) you can set different parameters. For instance, you can refocus the field
>>> viewer.focus = -20
The calculated output field is defined at zero focus. To move the focus position more into the sample, you have to move focus to negative values. Next, you can set the analyzer.
>>> viewer.analyzer = 90 #in degrees - vertical direction
>>> viewer.analyzer = "v" #or this, also works with "h","lcp","rcp","x","y" strings
If you do not wish to use the analyzer, simply remove it by specifying
>>> viewer.analyzer = None
To adjust the intensity of the input light you can set:
>>> viewer.intensity = 0.5
The intensity value is a multiplication coefficient for the computed spectra. So a value of 0.5 decreases the intensity by a factor of 0.5.
If input field was defined to be non polarized, you can set the polarizer
>>> viewer.polarizer = 0. # horizontal
You can set all these parameters with a single function call:
>>> viewer.set_parameters(intensity = 1., polarizer = 0., analyzer = 90, focus = -20)
When you are done with setting the microscope parameters you can calculate the transmitted specter
>>> specter = viewer.calculate_specter()
or, if you want to obtain RGB image:
>>> image = viewer.calculate_image()
The viewer also allows you to tune microscope settings dynamically.
>>> fig, ax = viewer.plot()
>>> fig.show()
Note
For this to work you should not use the matplotlib figure inline option in your python development environment (e.g. Spyder, jupyterlab, notebook). Matpoltlib should be able to draw to a new figure widget for sliders to work.
For more advanced image calculation, using windowing, reflection calculations, custom color matching functions please refer to the Tutorial.
Viewing direction¶
If a different viewing direction is required you must rotate the object and recompute the output field. Currently, you cannot rotate the optical data, but you can rotate the regular spaced director field and then construct the optical data as in examples above. There are two helper function to achieve rotations of the director field. If you want to do a 90 degrees y axis rotation you can do:
>>> dir90 = dtmm.rot90_director(director, axis = "y")
This rotates the whole computation box and the shape of the director field becomes
>>> dir90.shape
(96, 96, 60, 3)
This transformation is lossless as no data points are cropped and no interpolation is performed. You may want to crop data and add some border area to increase the size of the computation box and to match it to the original data. Alternative approach, and for a more general, lossy transformation you can use the dtmm.data.rotate_director()
function. For a 90 degree rotation around the y axis
>>> rmat = dtmm.rotation_matrix_y(np.pi/2)
>>> dir90i = dtmm.rotate_director(rmat,director)
Now the shape of the output director field is the same, and there are data points in the output that are out of domain in the original data and few data points in the original data were cropped in the proces. The out-of-domain data point are by default defined to be a zero vector
>>> dir90i[0,0,0] #the border is out of domain in the original data, so this is zero.
array([0., 0., 0.])
For a more general rotation, say a 0.3 rotation around the z axis (yaw), followed by a 0.4 rotation around the y axis (theta) and finally, a 0.5 rotation around the z axis (phi), there is a helper function that construct a rotation matrix by multiplying the three rotation matrices
>>> mat = dtmm.rotation_matrix((0.3,0.4,0.5))
It is up to the user to apply a mask or to specify the optical data parameters of these out of domain data points.
>>> mask = dtmm.sphere_mask((NLAYERS,HEIGHT,WIDTH),30)
>>> optical_block = dtmm.director2data(director, no = 1.5, ne = 1.6, mask = mask, nhost = 1.5)
Data IO¶
To save/load field data or optical (stack) data to a file for later use there are load and save functions:
>>> dtmm.save_field("field.dtmf", field_data_out)
>>> dtmm.save_stack("stack.dtms", optical_data)
>>> field_data = dtmm.load_field("field.dtmf")
>>> optical_data = dtmm.load_stack("stack.dtms")
Note
The save functions append .dtmf or .dtms extensions to the filename if extensions are not provided by user.
Increasing computation speed¶
dtmm
was developed with efficiency in mind. If you are running on Intel processors, to get the best performance, first make sure you have mkl_fft installed:
>>> import mkl_fft
You can further increase the computation speed. Before loading the package set these environment variables:
>>> import os
>>> os.environ["DTMM_DOUBLE_PRECISION"] = "0" #compile for single precision
>>> os.environ["DTMM_FASTMATH"] = "1" #use the fast math compilation option in numba
>>> os.environ["DTMM_TARGET_PARALLEL"] = "1" #use target='parallel' and parallel = True options in numba
Now load the package
>>> import dtmm
We now have the package compiled for best performance at the cost of computation accuracy. See Configuration & Tips for details and further tuning and configuration options.
Data Model¶
There are two types of data, one describing the optical properties of the sample and the second describing the electro-magnetic field of the in-going and out-going light. We will call the first one an optical data and the second one a field data. But first, let us define the coordinate system, units and conventions.
Coordinate system, units and conventions¶
Wavelengths are defined in nanometers.
Dimensions (coordinates) are defined in pixel units.
In the computations, size of the pixel is defined as a parameter (in nanometers).
Optical parameters (orientation of the optical axis) are defined relative to the reference laboratory coordinate frame xyz.
Propagation is said to be forward propagation if the wave vector has a positive z component.
Propagation is said to be backward propagation if the the wave vector has a negative z component.
Light enters the material at z=0 at the bottom of the sample and exits at the top of the sample.
The sample is defined by a sequence of layers - a stack. The first layer is the one at the bottom of the stack.
Internally, optical parameters are stored in memory as a C-contiguous array with axes (i,j,k,…) the axes are z, y, x, parameter(s).
For uniaxial material, the orientation of the optical axis is defined with two angles. is an angle between the z axis and the optical axis and
is an angle between the projection of the optical axis vector on the xy plane and the x axis.
For biaxial media, there is an additional parameter that together with
phi_m` define the three Euler angles for rotations of the frame around the z,y and z axes respectively.
Direction of light propagation (wave vector) is defined with two parameters, and
, or equivalently
and
, where
is an angle between the wave vector and the z axis, and
between the projection of the wave vector on the xy plane and the x axis.
Parameter is a fundamental parameter in transfer matrix method. This parameter is conserved when light is propagated through a stack of homogeneous layers.
Optical Data¶
Starting with version 0.7.0, the optical data format has changed. In the previous version, optical data, which is now termed an optical block, was a tuple. Instead, optical data is now a list of optical blocks. Optical block can be single or multiple-layer data. The optical data structure is defined below.
Nondispersive model¶
First we will explain the noondispersive model, where material parameters are treated as fixed (independent on wavelength). Let us build an example optical block data:
>>> import dtmm
>>> optical_block = dtmm.nematic_droplet_data((60, 128, 128),
... radius = 30, profile = "r", no = 1.5, ne = 1.6, nhost = 1.5)
Here we have generated some test optical data, a nematic droplet with a radius of 30 pixels placed in a bounding box of shape (60,128,128), that is, 60 layers of (height - y, width - x) of (128,128). Director profile is radial, with ordinary refractive index of 1.5 and extraordinary refractive index of 1.6 placed in an isotropic host with refractive index of 1.5. The optical data is a list of one element - a single optical block, which is tuple of three arrays
>>> thickness, material_eps, eps_angles = optical_block
thickness describes the thickness of layers in the optical data. It is an array of floats. It is measured in pixel units. In our case it is an array of ones of length 60:
>>> import numpy as np
>>> np.allclose(thickness, np.ones(shape = (60,)))
True
which means that layer thickness is the same as layer pixel size - a cubic lattice. Note that in general, layer thickness may not be constant and you can set any layer thickness. material_eps is an array of shape (60,128,128,3) of dtype “float32” or “float64” and describes the three eigenvalues of the dielectric tensor of the material. In our case we have two types of material, a host material (the one surrounding the droplet), and a liquid crystal material. We can plot this data:
>>> fig, ax = dtmm.plot_material(material_eps, dtmm.refind2eps([1.5,1.5,1.6]))
>>> fig.show()
which plots dots at positions where liquid_crystal is defined (where the refractive indices are [1.5,1.5,1.6]). This plots a sphere centered in the center of the bounding box, as shown in Fig.

LC is defined in a sphere . (Source code, png, hires.png, pdf)¶
material_eps is an array of shape (60,128,128,3). Material is defined by three real (or complex) dielectric tensor eigenvalues (refractive indices squared):
>>> material_eps[0,0,0]
array([2.25, 2.25, 2.25])
>>> material_eps[30,64,64]
array([2.25, 2.25, 2.56])
The real part of the dielectric constant is the refractive index squared and the imaginary part determines absorption properties.
eps_angles is an array of shape (60,128,128,3) and describe optical axis angles measured in radians in voxel. For isotropic material these are all meaningless and are zero, so outside of the sphere, these are all zero:
>>> eps_angles[0,0,0]
array([0., 0., 0.])
while inside of the sphere, these three elements are
>>> eps_angles[30,64,64] #z=30, y = 64, x = 64
array([0. , 0.95531662, 0.78539816])
The first element is always 0 because it defines the angle (used in biaxial materials), the second value describes the
angle, and the last describes the
angle.
We can plot the director around the center (around the point defect) of the droplet by
>>> fig, ax = dtmm.plot_angles(eps_angles, center = True, xlim = (-5,5),
... ylim = (-5,5), zlim = (-5,5))
>>> fig.show()
Note
matplotlib cannot handle quiver plot of large data sets, so you have to limit dataset visualization to a small number of points. The center argument was used to set the coordinate system origin to bounding box center point and we used xlim, ylim and zlim arguments to slice data.

LC director of the nematic droplet near the center of the sphere. Director is computed from director angles. There is a point defect in the origin. (Source code, png, hires.png, pdf)¶
Dispersive model¶
If you want to simulate wavelength dispersion, epsv must no longer be a constant array, but you must define it to be a callable. For each wavelength, the algorithm computes the epsv array from the provided callable. For instance, to use Cauchy approximation with two coefficients, there is a helper object to create such callable:
>>> epsc = EpsilonCauchy(shape = (60,128,128), n = 2)
>>> epsc.coefficients[...,0] = (material_eps)**0.5 # a term, just set to refractive index
>>> epsc.coefficients[...,0:2,1] = 0.005*(material_eps[...,0:2])**0.5 # b term ordinary
>>> epsc.coefficients[...,2,1] = 0.005*(material_eps[...,2])**0.5 # b term extraordinary
Now you can compute the epsilon tensor eigenvalues by calling the callable with the wavelength in nanometers as an argument, e.g.:
>>> material_eps = epsc(550)
To use the dispersive material in computations, you must pass the following optical data to the tranfer_field function:
>>> optical_data = [(thickness, epsc, material_angles)]
Note that you may create your own callable for material_eps, but the callable must return a valid numpy array describing the epsilon tensor eigenvalues that is compatible with material_angles matrix and the thickness array.
Multi-block data¶
Above, we demonstrated the usage of single-block data. A multi-block data consists of several data blocks. These may be multi-layer blocks, as in the examples above, or single-layer data. For instance, a uniaxial retarder of a thickness of 1. and with optical axes in the deposition plane and rotated by 45 degrees with respect to the horizontal axis is:
>>> retarder_data = [(1.,(1.5**2, 1.5**2, 1.6.**2),(0., np.pi/2, np.pi/4))]
Above retarder data is a valid optical data. It describes a single block, which itself is a single-layer data. Note that we could have set the block as a multi-layered block with the length of layers equal to 1, e.g.:
>>> retarder_data = [((1.,),((1.5**2, 1.5**2, 1.6.**2),),((0., np.pi/2, np.pi/4)),)]
For 2D blocks (1D grating structure) you can do:
>>> grating_data = [(1.,((1.5**2, 1.5**2, 1.6.**2),)*128,((0., np.pi/2, np.pi/4),))*128)]
All examples above are actually shorthand for creating 1D or 2D data. Internally, true data format is 3D. You can validate data format (to make it 3D) by calling:
>>> validated_grating_data = dtmm.data.validate_optical_data(grating_data)
This function converts the data to a valid 3D optical data format. For 1D and 2D input data, it adds dimensions to optical blocks. You do not need to validate optical data yourself, as this is done internally when calling the computation functions. Now we have:
>>> d,epsv,epsa = validated_grating_data[0] #take first (and only) block
>>> epsv.shape
(1,1,128,3)
>>> epsa.shape
(1,1,128,3)
You can add blocks together to form a new stack of data:
>>> new_optical_data = retarder_data + optical_data + grating_data
>>> validated_optical_data = dtmm.data.validate_optical_data(new_optical_data, shape = (128,128), wavelength = 500)
There are two things to notice here. First, we used the wavelength argument for the validation. This ensures that we evaluate the refractive indices (epsilon values) at a given wavelength because we used dispersive data for one of the blocks. Second, we used the shape argument, which describes the requested cross-section shape of the optical blocks. Because we mix different dimensions of the blocks (1D, 2D, and 3D in our case), we have to provide a common shape for all blocks to which each block is broadcasted.
Function dtmm.data.validate_optical_data()
raises an exception if it cannot produce a valid optical data, if shapes of the blocks do not match. It is up to the user to prepare each data block with a cross-section shapes which can all broadcast together.
Layered data¶
Finally, there is yet another valid optical data format, labeled layered data. You can build layers data from list of blocks. E.g.:
>>> layers = dtmm.data.layered_data(validated_optical_data)
>>> isinstance(layers, list)
True
>>> len(layers)
62
which constructs a list of 62 elements, 2 for the extra two blocks, and 60 for the LC block. Each element of the layered_data now describes a single layer:
>>> d, epsv, epsa = layers[0]
>>> d
1.
Field Data¶
>>> import numpy as np
>>> pixelsize = 100
>>> wavelengths = [500,600]
>>> shape = (128,128)
>>> field_data = dtmm.illumination_data(shape, wavelengths,
... pixelsize = pixelsize)
Here we used a field.illumination_data()
convenience function that builds the field data for us. We will deal with colors later, now let us look at the field_waves data. It is a tuple of two ndarrays and a scalar :
>>> field, wavelengths, pixelsize = field_data
Now, the field array shape in our case is:
>>> field.shape
(2, 2, 4, 128, 128)
which should be understood as follows. The first axis is for the polarization of the field. With the field.illumination_data()
we have built initial field of the incoming light that was specified with no polarization, therefore, field.illumination_data()
build waves with x and y polarizations, respectively, so that it can be used in the field viewer later. The second axis is for the wavelengths of interest, therefore, the length of this axis is 2, as
>>> len(wavelengths)
2
The third axis is for the EM field elements, that is, the E_x, H_y, E_y and H_x components of the EM field. The last two axes are for the height, width coordinates (y, x).
A multi-ray data can be built by providing the beta and phi parameters (see the Coordinate system, units and conventions for definitions):
>>> field_data = dtmm.illumination_data(shape, wavelengths,
... pixelsize = pixelsize, beta = (0,0.1,0.2), phi = (0.,0.,np.pi/6))
>>> field, wavelengths, pixelsize = field_data
>>> field.shape
(3, 2, 2, 4, 128, 128)
If a single polarization, but multiple rays are used, the shape is:
>>> field_data = dtmm.illumination_data(shape, wavelengths, jones = (1,0),
... pixelsize = pixelsize, beta = (0,0.1,0.2), phi = (0.,0.,np.pi/6))
>>> field, wavelengths, pixelsize = field_data
>>> field.shape
(3, 2, 4, 128, 128)
How does it look like? Let us apply a circular aperture to the field and plot it. The field is a cross section of a plane wave with wave vector defined by the wavelength, pixel size and direction (beta, phi) as can be seen in the images.

The real part of the Ex component of the EM field for the three directions (beta, phi) and two wavelengths. Top row is for 500nm data, bottom row is 600nm data. (Source code, png, hires.png, pdf)¶
Field vector¶
For 1D and 2D simulations with a non-iterative algorithm we use field vector instead. There are conversion functions that you can use to build field data from field vector and vice-versa, e.g:
>>> fvec = dtmm.field.field2fvec(field)
>>> fvec.shape
(3, 2, 128, 128, 4)
>>> field = dtmm.field.fvec2field(fvec)
>>> field.shape
(3, 2, 4, 128, 128)
Jones field¶
For 2x2 methods, the computation is done using jones fields, which is Electric field-only representation of the electro-magnetic field. To complete the transform you need to add additional info about the material and field. One can convert the field data to jones field by:
>>> jones = dtmm.field.field2jones(field, beta = 0, phi = 0, epsv = (1,1,1))
>>> jones.shape
(3, 2, 2, 128, 128)
Above transform assumes that field has a well-defined wave vector and is propagating in vacuum along z direction. For wide beams of light, the assumption of a well-defined wave vector is valid, but for narrow beams, or for beams with high frequency components, you should instead call the function without the beta and phi terms and provide the wave numbers, e.g.:
>>> jones = dtmm.field.field2jones(field, dtmm.wave.k0(wavelengths, pixelsize), epsv = (1,1,1))
The above transform takes the modes of the field and takes the forward propagating part (you can also compute back-propagating part using mode = -1 argument) of the field, then it takes the Ex and Ey components of the field and stores them into the output array. Note that the resulting jones field is not a true Jones vector (except for beta = 0), because the Electric field components of the jones field are represented in the laboratory coordinate frame. The light intensity is not simply . You should convert back to EM field, if you plan to compute anything with jones field.
Tutorial¶
Below you will find a series of examples. You can run the examples by downloading the source code (see links in the image captions). You can also browse the examples/ folder in the source distribution or at the GitHub repository, where you will find some additional examples not covered in this tutorial.
Jones calculus (1D)¶
You can use the package for simple normal incidence Jones calculus. In the dtmm.jones
you will find all the functionality to work with jones calculus. For example, we can compute the transmittance properties of a simple Twisted Nematic director profile. We compute wavelength-dependent transmittance of normally white and normally black TN modes. We build a left-handed twisted nematic in a 4 microns cell and in the first minimum condition - max transmission at 550 nm.
The matrix creation functions in the jones module obey numpy broadcasting rules, so we can build and multiply matrices at different wavelengths simultaneously. See the source code of the example below.

Shows how to perform a simple Jones calculus. (Source code, png, hires.png, pdf)¶
Transfer Matrix Method (1D)¶
For simulations in 1D you have several options using tmm
. You can use the standard 4x4 transfer matrix approach, which allows you to study reflections from the surface, and there are several options for transmission calculations. In addition to 4x4, you can take the scattering matrix formulation (the 2x2) approach without reflections or with a single fresnel reflection. The 4x4 approach also allows you to perform single-reflection calculation (disabling interference effect) in case you have thicker samples. the details on the he 4x4 transfer matrix approach can be found tin the literature, e.g. Birefringent Thin Films and Polarizing Elements by McCall, Hodgkinson and Wu.
Run the source code and read the comments of the examples below to learn how to use the tools for 1D analysis using 4x4 approach.
Single layer reflection¶
In this example, we calculate reflections off a single 2 micron thick layer of material with refractive index of 1.5. See the source code for additional detail of the example below.

Reflection and transmission properties of a single layer material. (Source code, png, hires.png, pdf)¶
Cholesteric reflection¶
In this example we calculate reflections off a cholesteric material. See the source code for additional details of the example below.

Reflection and transmission properties of a cholesteric LC with a reflection band at 550 nm. (Source code, png, hires.png, pdf)¶
Twisted nematic transmission¶
In this example we compute the transmittance through 90 degree twisted nematic configured in first minimum condition (4 micron cell, refractive index anisotropy of 0.12). Here we demonstrate and show differences between the 4x4 approach and two versions of 2x2 approach - with reflections and without.

Reflection and transmission properties of a twisted nematic film (with film-to-air interfaces) (Source code, png, hires.png, pdf)¶
2D simulations¶
For 2D simulations, you can use the non-iterative 2D 4x4 approach developed in tmm2d
. It works by writing the 4x4 matrices in Fourier space. At a given z position in space, and for a given computation box size and resolution, each wave can be described as a sum of N propagating modes. Therefore, for each of the inhomogeneous layers one writes a NxNx4x4 transfer matrix. Because of the NxN complexity, this approach works well for smaller sized computation cells involving only few modes. See the examples below for details.
Cholesteric reflection grating¶
In this example we calculate reflections from a tilted cholesteric sample, which produces a grating and mirror-like reflections. We plot optical microscope image formation and reflection efficiency for LCP and RCP input polarizations.
3D simulations¶
In 3D, one may be tempted to develop the same non-iterative approach as for 2D. However, this becomes impractical because of the size of the matrices and computational complexity. Although you can find the implementation in tmm3d
, this was developed for reference and testing, and it was not really meant to be useful in practice. Instead, for computations in 3D, we use an iterative algorithm. Instead of writing the transfer matrices and multiplying the matrices together to form a material characteristic matrix, one works with field vector in real space and transfers it through the layers in a split-step fashion. The layer is viewed as a thin inhomogeneous birefringent film and a thick homogeneous layer.
First, the field is transferred through the thin film in real space, acquiring phase change (with reflections), then the field is propagated by matrix multiplication if Fourier space. It is a bit more technical than that, and details of the non-iterative method is given in some future paper. Below you will find some technical information and examples of use.
Interference and reflections¶
By default, interference and reflections are neglected in the computation. You can enable interference by specifying how many passes to perform and using the 4x4 method
>>> field_data_out = dtmm.transfer_field(field_data_in, optical_data, npass = 5, method = "4x4")
or using the 2x2 method, assuming most reflections come from interlayer reflections and not from the inhomogeneities, in example, reflactions from the first air-sample interface and the last sample-air interface jou can do
>>> field_data_out = dtmm.transfer_field(field_data_in, optical_data, reflection = 1, npass = 3, method = "2x2")
If reflections come from the inhomogeneities you should call
>>> field_data_out = dtmm.transfer_field(field_data_in, optical_data, reflection = 2, npass = 3, method = "2x2")
Read further for details…
4x4 method¶
Dealing with interference can be tricky. The DTMM implements an adapted 4x4 transfer matrix method which includes interference, however, one needs to perform multiple passes (iterations) to compute the reflections from the material. With transfer matrix method one computes the output field (the forward propagating part and the backward propagating part) given the defined input field. In a typical experiment, the forward propagating part of the input field is known - this is the input illumination light. However, the backward propagating part of the input field is not know (the reflection from the surface of the material) and it must be determined.
The procedure to calculate reflections is as follows. First the method computes the output field by assuming zero reflections, so that the input field has no back propagating part. When light is transferred through the material, we compute both the forward and the backward propagating part of the output field. The back propagating part of the output field cancels all reflected waves from the material and the input light has no back propagating component of the field. To calculate reflections off the surface one needs to do it iteratively:
Initially input light is defined with zero reflections and transferred through the stack to obtain the output field.
After the first pass (first field transfer calculation), output light is modified so that the back propagating part of the field is completely removed. Then this modified light is transferred again through the stack in backward direction to obtain the modified input light which includes reflections.
After the second pass. Input light is modified to so that forward propagating part of the field matches the initial field_data, and the field is transferred through the stack again..
For low reflective material, three passes are usually enough to obtain a reasonable accurate reflection and transmission values. However, in highly reflective media (cholesterics) more passes are needed.
The calculation is done by setting the npass and norm arguments:
>>> field_data_out = dtmm.transfer_field(field_data_in, optical_data, npass = 3, norm = 2)
The npass argument defines number of passes (field transfers). You are advised to use odd number of passes when dealing with reflections. With odd passes you can inspect any residual back propagating field left in the output field_data, to make sure that the method has converged.
In highly reflective media, the solution may not converge. You must play with the norm argument, which defines how the output field is modified after each even pass.
with norm = 0 the back propagating part is simply removed, and the total intensity of the forward propagating part is rescaled to conserve total power flow. This method works well for weak reflections.
with norm = 1 the back propagating part is removed, and the amplitude of the fourier coefficients of the forward propagating part are modified so that power flow of each of the modes is conserved. This method work well in most cases, especially when reflections come from mostly the top and bottom surfaces.
with norm = 2, during each even step, a reference non-reflecting and non-interfering wave is transferred through the stack. This reference wave is then used to normalize the forward propagating part of the output field. Because of the additional reference wave calculation this procedure is slower, but it was found to work well in any material (even cholesterics).
2x2 method¶
The 2x2 method is a scattering method, it is stable (contrary to the 4x4 method) and it can also be used to compute interference. When npass>1, the method calculates fresnel reflections from the layers and stores intermediate results. As such, it is much more memory intensive as the 4x4 method (where intermediate results are not stored in memory). However, it is prone to greater numerical noise when dealing with highly reflecting media, such us cholesterics. Also, large number of passes are required for highly reflective media, so it can be used for weakly reflecting material only.
There are two reflection calculation modes. In the reflection = 1 mode, the field is Fourier transformed and mode coefficients are reflected from the interface between the effective layers (specified by the eff_data argument). If you want to calculate reflections from a stack of homogeneous layers, this gives an exact reflection calculation. For instance, to take into account reflections from the input and output interfaces, simply do
>>> field_data_out = dtmm.transfer_field(field_data_in, optical_data, reflection = 1, npass = 3, method = "2x2")
In the example above there will be no interlayer reflections in the sample, because the optical data is seen as an isotropic effective data with a mean refractive index when treating diffraction and reflection in light propagation. But, input and output layers have different refractive indices (n=1 by default), so you will see reflections from these interfaces.
In the reflection = 2 mode, the field is reflected from the inhomogeneous layers in real space. Consequently, this is not exact if the layers are homogeneous and the input light beam has a large number of off-axis waves, but it can be used when you want to see reflections from local structures. To take into account the dependence of off-axis wave reflection coefficient with the mode coefficient you must increase the diffraction quality, e.g.:
>>> field_data_out = dtmm.transfer_field(field_data_in, optical_data, diffraction = 5, reflection = 2, npass = 3, method = "2x2")
In the example above, reflections are cumulatively acquired from each of the interfaces in the optical data, including reflections from the input and output interfaces. If main reflections come from the input and output interfaces this will not be as accurate as reflection = 1 mode, but it will be more accurate if reflections are mainly due to the inhomogeneities in the optical data.
Examples¶
Surface reflections¶
In this example we calculate reflection and transmission of a spatially narrow light beam that passes a two micron thick isotropic layer of high refractive index of n = 4 at an angle of beta = 0.4. Already at three passes, the residual data is almost gone.
One clearly sees beam walking and multiple reflections and interference from both surfaces. See the examples/reflection_isolayer.py for details.

(png, hires.png, pdf) Reflection and transmission of an off-axis (beta = 0.4) light beam from a single layer of two micron thick high refractive index material (n=4). Intensity is increased to a value of 100, to see the multiple reflected waves, (Source code)¶

(png, hires.png, pdf) Reflection and transmission of an off-axis (beta = 0.4) light beam from a single layer of two micron thick high refractive index material (n=4). Intensity is increased to a value of 100, to see the multiple reflected waves, (Source code)¶

(png, hires.png, pdf) Reflection and transmission of an off-axis (beta = 0.4) light beam from a single layer of two micron thick high refractive index material (n=4). Intensity is increased to a value of 100, to see the multiple reflected waves, (Source code)¶

(png, hires.png, pdf) Reflection and transmission of an off-axis (beta = 0.4) light beam from a single layer of two micron thick high refractive index material (n=4). Intensity is increased to a value of 100, to see the multiple reflected waves, (Source code)¶
Cholesterics¶
In this example, we use multiple passes to compute reflections of the cholesteric droplet. For cholesterics one should take the norm = 2 argument in the computation of the tranfered field.
The droplet is a left-handed cholesteric with pitch of 350 nm, which results in a strong reflection of left-handed light of wavelength 520 nm (350*1.5 nm). Already with npass = 5, the residual field has almost vanished.
In the example below, we simulated propagation of non-polarized light with beta parameter beta = 0.2. See the examples/cholesteric_droplet.py for details.

(png, hires.png, pdf) Reflection and transmission properties of a cholesterol droplet. (Source code)¶

(png, hires.png, pdf) Reflection and transmission properties of a cholesterol droplet. (Source code)¶

(png, hires.png, pdf) Reflection and transmission properties of a cholesterol droplet. (Source code)¶
Standard TMM - no diffraction¶
You can use the dtmm package for 1D calculation. There are two options. Either you create a single pixel optical data that describes your 1D material and use the functions covered so far, or you do a standard Berreman or Jones calculation by computing the transfer matrices, and the reflectance and transmittance coefficients with functions found in dtmm.tmm
. For coherent reflection calculation of complex 1D material this may be better/faster than using the dtmm.transfer.transfer_field()
. Note that the diffractive method uses iterative algorithm to calculate coherent effects. With a standard 4x4 method in 1D case, these are done in a single step.
In the dtmm.tmm
module you will find low-level implementation of the TMM method, and some high level function to simplify computations and use. Here we go through the high level API, while for some details on the implementation you should read the source code of the examples below.
Basics¶
Computation is performed in two steps. First we build a characteristic matrix of the stack, then we calculate transmitted (and reflected) field from a given field vector. Field vector now is a single 4-component vector. We will demonstrate the use on a 3D data that we were working on till now.
>>> d, epsv, epsa = dtmm.nematic_droplet_data((NLAYERS, HEIGHT, WIDTH),
... radius = 30, profile = "x", no = 1.5, ne = 1.6, nhost = 1.5)
>>> f,w,p = dtmm.illumination_data((HEIGHT, WIDTH), WAVELENGTHS, diffraction = False,
... pixelsize = PIXELSIZE, beta = 0., phi = 0.)
First we need to transpose the field data to field vector
>>> fin = dtmm.field.field2fvec(f)
Next we need to build phase constants (layer thickness times wavenumber)
>>> kd = [x*(dtmm.k0(WAVELENGTHS, PIXELSIZE))[...,None,None] for x in d]
Here we also added two axes for broadcasting. The epsv[i] and epsa[i] arrays are of shape
(HEIGHT, WIDTH, 3), we need to add two axes of len(1) to elements kd[i] because numpy broadcasting rules apply to arguments of the dtmm.tmm.stack_mat()
that is used to compute the characteristic matrix. So now you do:
>>> cmat = dtmm.tmm.stack_mat(kd, epsv, epsa)
which computes layer matrices Mi and multiplies them together so that the output matrix is M = Mn…M2.M1. Then you call dtmm.tmm.reflect()
to compute the tranmited and reflected fields (the reflected field is added to input field).
>>> smat = dtmm.tmm.system_mat(cmat = cmat) #compute system matrix
>>> rmat = dtmm.tmm.reflection_mat(smat) #compute reflectance matrix
>>> fout = dtmm.tmm.reflect(fin,rmat)
That is it. You can now view this field with the field_viewer, but first you need to transpose it back to the original field data shape.
>>> field_data = dtmm.field.fvec2field(fout),w,p
>>> viewer = dtmm.field_viewer(field_data, diffraction = False)
Note the use of diffraction= False option which tells the field viewer that computed data is not diffraction-limited (and has not been calculated with the transfer_field dfunction and diffraction>0 argument). This way, data is displayed as is, without any plane-wave decomposition and filtering (by cutting non-propagating high frequency modes).
The stack_mat()
takes an optional parameter method which can take a string value of “4x4”, “2x2” or “4x2”. The “4x4” is for standard Berreman - interference enabled calculation, The “4x2” method is for a 4x4 method, but with interference disabled by setting the phase matrix element to zeros for back propagating waves. This method is equivalent to method = “2x2” and reflection = 2 arguments in the dtmm.transfer.transfer_field()
. The “2x2” method is for jones calculation. This method is equivalent to method = “2x2” and reflection = 0 arguments in the dtmm.transfer.transfer_field()
.
Nematic droplet example¶
See the source code of the examples to see additional details.
An example of a nematic droplet with planar director orientation, computed using 4x4 method with interference, 4x4 method without interference (single reflection) and 2x2 method with no reflections at all. All of these examples could be computed with transfer_field functions and diffraction = False argument… and the results of both methods should be identical (up to numerical precision).

(png, hires.png, pdf) An example of extended jones calculation, berreman 4x4 with interference and with interference disabled methods to compute transmission of a white light through the nematic droplet with a planar director alignment, viewed between crossed polarizers. (Source code)¶

(png, hires.png, pdf) An example of extended jones calculation, berreman 4x4 with interference and with interference disabled methods to compute transmission of a white light through the nematic droplet with a planar director alignment, viewed between crossed polarizers. (Source code)¶

(png, hires.png, pdf) An example of extended jones calculation, berreman 4x4 with interference and with interference disabled methods to compute transmission of a white light through the nematic droplet with a planar director alignment, viewed between crossed polarizers. (Source code)¶

(png, hires.png, pdf) An example of extended jones calculation, berreman 4x4 with interference and with interference disabled methods to compute transmission of a white light through the nematic droplet with a planar director alignment, viewed between crossed polarizers. (Source code)¶

(png, hires.png, pdf) An example of extended jones calculation, berreman 4x4 with interference and with interference disabled methods to compute transmission of a white light through the nematic droplet with a planar director alignment, viewed between crossed polarizers. (Source code)¶
Field viewer¶
In addition to the Polarizing Optical Microscope viewer which was covered in the quick start guide, there is also a FieldViewer. The difference between the FieldViewer and POMViewer is that the latter works with 2x2 matrices, whereas FieldViewer works with 4x4 matrices.
Here we will cover some additional configuration options for the FieldViewer. The field viewer can be used to inspect the output field_data, or to inspect the bulk field data.
Projection mode¶
One powerful feature of the FieldViewer is the ability to project the waves and isolate the forward or backward propagating waves. This is how the images of the examples above were created, so to take the transmitted part of the field do:
>>> viewer = dtmm.field_viewer(field_data_out, mode = "t") #the transmitted part
to view the reflected part of the field do:
>>> viewer = dtmm.field_viewer(field_data_out, mode = "r") #the reflected part
When field viewer is called without the mode argument it performs no projection calculation. A power flow is calculated directly from the electro-magnetic field (Poynting vector times layer normal). As such, the power flow can be positive or negative. A negative power flow comes from the back propagating waves and it has to be stressed that negative values are clipped in the conversion to RGB. Therefore, when dealing with reflections and interference calculations, you should be explicit about the projection mode.
The numerical aperture¶
Another parameter that you can use is the betamax parameter. Some explanation on this is below, but in short, with betamax parameter defined in the field_viewer function you can simulate the finite numerical aperture of the objective. So to simulate an image taken by a microscope with NA of 0.4 do:
>>> viewer = dtmm.field_viewer(field_data_out, mode = "t", betamax = 0.4)
And if you want to observe ideal microscope lens image formation, set betamax to the value of refractive index). For instance an oil-immersion objective with n = 1.5 and NA 1.3 do
>>> viewer = dtmm.field_viewer(field_data_out, mode = "t", betamax = 1.3, n = 1.5)
but of course, here it is up to the user to calculate the output field for the output refractive index of 1.5.
Viewing bulk data¶
The field_viewer function can also be used to show bulk EM data in color. Here you will generally use it as
>>> viewer = dtmm.field_viewer(field_bulk_data, bulk_data = True)
Now the “focus” parameter has a role of selecting a layer index and the viewer shows the power of the EM field in the specified layer.

Bulk viewer - viewing field in a specified layer. (Source code, png, hires.png, pdf)¶
The refractive index n, and betamax parameters are meaningless when using the field_viewer to visualize bulk data, except if you define a transmission or reflection mode. In this case, the viewer project the EM field and calculates the forward or backward propagating parts and removes the waves with beta value larger than the specified betamax parameter before calculating the intensity.
POM viewer¶
The Polarizing Optical Microscope viewer was covered in the quick start guite. The difference between the FieldViewer and POMViewer is that the latter works with 2x2 matrices, whereas FieldViewer works with 4x4 matrices. Internally, the POMViewer converts the field data to E-field (or jones field data):
>>> jones = dtmm.field.field2jones(f,dtmm.k0(WAVELENGTHS, PIXELSIZE))
This is done automatically when you call the:
>>> pom = dtmm.pom_viewer(field_data)
See the quick start quite for usage details.
Calculation accuracy¶
Effective medium¶
The algorithm uses a split-step approach where the diffraction calculation step is performed assuming a homogeneous effective medium. What this means is that if the input optical data consists of homogeneous layers, the algorithm is capable of computing the exact solution. However, the accuracy of the calculated results will depend on how well you are able to describe the effective medium of the optical stack. By default, isotropic medium is assumed, that is, for each layer in the stack an isotropic layer is defined and calculated from the input optical data parameters. You can also explicitly define the medium as:
>>> out = dtmm.transfer_field(field_data, data, eff_data = "isotropic")
If the layer cannot be treated as an isotropic layer on average, you should tell dtmm
to use anisotropic layers instead, e.g.:
>>> out = dtmm.transfer_field(field_data, data, eff_data = "uniaxial")
or
>>> out = dtmm.transfer_field(field_data, data, eff_data = "biaxial")
Note
The ‘biaxial’ option is considered experimental. In the calculation of the diffraction matrix for biaxial medium the algorithm may not be able to properly sort the eigenvectors for beta values above the critical beta (for waveguiding modes). These modes are filtered out later in the process and controlled by the betamax parameter, so in principle, mode sorting is irrelevant for propagating modes. Consequently, you may see some warnings on mode sorting, but this should not affect the end results. This issue will be fixed at some point.
Internally, when specifying eff_data argument, the algorithm performs calculation of the effective medium with
>>> eff_data = dtmm.data.effective_data(data, "uniaxial")
which computes the spatially-varying dielectric tensor for each of the layers, performs averaging, and then converts the averaged tensor to eigenframe and converts it to the desired symmetry. You can use the above function to prepare effective layers and pass the computed result to
>>> out = dtmm.transfer_field(field_data, data, eff_data = eff_data)
For even higher accuracy, in more non-uniform systems where the mean dielectric tensor varies considerably across the layers you should define the effective medium for each of the layers separately:
>>> n_layers = len(epsv)
>>> eff_data = dtmm.data.effective_data(data, [("uniaxial",)*n_layers])
which performs averaging of the dielectric tensor only across the individual layer and defines a unique effective data for each of the layers. You can also do:
>>> out = dtmm.transfer_field(field_data, data, eff_data = [("uniaxial",)*n_layers])
You can also use the split_layers argument, which does essentially the same thing:
>>> out = dtmm.transfer_field(field_data, data, eff_data = "uniaxial", split_layers = True)
You can also mix the symmetry e.g.
>>> eff_data = [("uniaxial","isotropic","biaxial",...)] #length must match the number of layers
Please note that having different effective layers in the system significantly slows down the computation because the diffraction matrices need to be calculated for each of the layers, whereas if
>>> eff_data = "uniaxial"
the calculation of the diffraction matrix is done only once for each block. .. note:
You can set the default medium in the configuration file. See :ref:`optimization` for details.
Diffraction quality¶
Diffraction calculation can be performed with different levels of accuracy. By default, diffraction and transmission through the inhomogeneous layer is calculated with a single step, assuming the field is a beam of light with a well defined wave vector. If your sample induces waves with higher frequencies, you should split the field into a sum of beams by defining how many beams to use in the diffraction calculation. For instance,
>>> out = dtmm.transfer_field(field_data, data, diffraction = 3)
in the diffraction calculation step, the method takes beams defined with beta parameters in a 3x3 grid of beta_x beta_y values defined between -betamax and +betamax, so a total of 9 beams (instead of a single beam when diffraction = 1). Therefore this will take significantly longer to compute. You can use any sensible integer value - this depends on the pixel size and domain size. For calculation of 100x100 grid with pixelsize of 50 nm and 500nm wavelength, the maximum sensible value is 100*50/500=10, but generally, above say diffraction = 7 you will not notice much improvement, but this depends on the material of course. In the extreme case, the most accurate calculation can be done by specifying
>>> out = dtmm.transfer_field(field_data, data, diffraction = np.inf)
or with a value of
>>> out = dtmm.transfer_field(field_data, data, diffraction = -1)
This triggers a full treatment of diffraction, transfers all waves within the beta < betamax. This method is very slow, and should not be used generally, except for very small samples.
Try experimenting yourself. As a rule of thumb, diffraction = 1 gives a reasonable first approximation and is very fast to compute, and with diffraction = 5 you are very close to the real thing, but about 5*5 slower to compute.
In the examples below we show difference between several diffraction arguments (0,1,5). With diffraction = 0, the method does not include diffraction effects. With diffraction = 1 and 5, one can see that due to diffraction a halo ring appears and the appearance of colors is slightly different for all three methods.

(png, hires.png, pdf) A comparison of diffraction = 0, diffraction = 1, and diffraction = 5 transmission calculations of same radial nematic droplet. See source for details on optical parameters. (Source code)¶

(png, hires.png, pdf) A comparison of diffraction = 0, diffraction = 1, and diffraction = 5 transmission calculations of same radial nematic droplet. See source for details on optical parameters. (Source code)¶

(png, hires.png, pdf) A comparison of diffraction = 0, diffraction = 1, and diffraction = 5 transmission calculations of same radial nematic droplet. See source for details on optical parameters. (Source code)¶
Note
You can also disable diffraction calculation step by setting the diffraction = False to trigger a standard 2x2 jones calculation or 4x4 Berreman calculation (when method = 4x4)
On the betamax parameter¶
The betamax parameter defines the maximum value of the plane wave beta parameter in the diffraction step of the calculation. When decomposing the field in plane waves, the plane wave with the beta parameter higher than the specified betamax parameter is neglected. In air, the maximum value of beta is 1. A plane wave with beta = 1 is a plane wave traveling in the lateral direction (at 90 degree with respect to the layer normal). If beta is greater than 1 in air, the plane wave is no longer a traveling wave, but it becomes an evanescent wave and the propagation becomes unstable in the 4x4 method (when method = “4x4” is used in the computation). In a medium with higher refractive index, the maximum value for a traveling wave is the refractive index beta=n. Generally you should use betamax < n, where n is the lowest refractive index in the optical stack (including the input and output isotropic layers). Therefore, if you should set betamax < 1 when the input and output layers are air with n=1. Some examples:
>>> out = dtmm.transfer_field(field_data, data, betamax = 0.99, method = '4x4', nin = 1, nout = 1) #safe
>>> out = dtmm.transfer_field(field_data, data, betamax = 1, method = '4x4', nin = 1, nout = 1) #unsafe
>>> out = dtmm.transfer_field(field_data, data, betamax = 1.49, method = '4x4', nin = 1.5, nout = 1.5) #safe
>>> out = dtmm.transfer_field(field_data, data, betamax = 1.6, method = '4x4', nin = 1.5, nout = 1.5) #unsafe
When dealing only with forward waves (the 2x2 approach).. the method is stable, and all above examples are safe to execute:
>>> out = dtmm.transfer_field(field_data, data, betamax = 2, method = '2x2') #safe
However, there is one caveat.. when increasing the diffraction accuracy it is also better to stay in the betamax < 1 range to increase computation speed. For instance, both examples below will give similarly accurate results, but computation complexity is higher when we use higher number of waves in the diffraction calculation step:
>>> out = dtmm.transfer_field(field_data, data, betamax = 2, diffraction = 5) #safe but slow
>>> out = dtmm.transfer_field(field_data, data, betamax = 1, diffraction = 3) #safe and faster
Color Conversion¶
In this tutorial, you will learn how to transform specter to RGB colors using CIE 1931 standard observer color matching function (see CIE 1931 wiki pages for details on XYZ color space). You will learn how to define the light source specter and compare the simulated data with experiments (images obtained by a color or a monochrome camera). First, we will go through some basics, but you can skip this part and go directly to Color cameras or Monochrome cameras.
Background¶
In the dtmm.color
, there is a limited set of functions for converting computed specters to RGB images. The module is not a full color engine, so only a few color conversion functions are implemented. The specter is converted to color using a CIE 1931 color matching function (CMF). Color conversion is performed as follows. Spectral data is first converted to XYZ color space using the CIE 1931 standard observer (5 nm tabulated) color matching function data. The image is then converted to RGB color space (using a D65 reference white point) as specified in the sRGB standard (see sRGB wiki pages for details on sRGB color space). Data values are then clipped to (0.,1.), and finally, sRGB gamma transfer function is applied.
CIE 1931 standard observer¶
CIE 1931 color matching function can be loaded from a table with
>>> import dtmm.color as dc
>>> import numpy as np
>>> cmf = dc.load_cmf()
>>> cmf.shape
(81, 3)
The table is a 5nm tabulated data (between 380 and 780 nm) of 2-deg XYZ tristimulus values - a numerical representation of the human vision system with three cones. This table is used to convert specter data to XYZ color space.

XYZ tristimulus values. (Source code, png, hires.png, pdf)¶
D65 standard illuminant¶
CIE also defines several standard illuminants. We will work with a D65 standard illuminant, which represents natural daylight. Its XYZ tristimulus value is used as a reference white color in the sRGB standard.
>>> spec = dc.load_specter()

D65 color specter from 5nm tabulated data. (Source code, png, hires.png, pdf)¶
XYZ Color Space¶
The CMF table and D65 specter are defined so that resulting RGB image gives white color. The specter dimensions have to match CMF table dimensions to convert the specter to XYZ color space. CIE 1931 CMF is defined between 380 and 780 nm, while the D65 specter is defined between 300 and 830 nm. Let us match the specter to CMF by interpolating D65 tabulated data at CMF wavelengths:
>>> wavelengths, cmf = dc.load_cmf(retx = True)
>>> spec = dc.load_specter(wavelengths)
Now we can convert the specter to XYZ value with:
>>> dc.spec2xyz(spec,cmf)
array([2008.69027494, 2113.45495097, 2301.13095117])
Typically you will want to work with a normalized specter:
>>> spec = dc.normalize_specter(spec,cmf)
>>> xyz = dc.spec2xyz(spec,cmf)
>>> xyz
array([0.95042966, 1. , 1.08880057])
Here we have normalized the specter so that the resulting XYZ value has the Y component equal to 1 (full brightness).
SRGB Color Space¶
Resulting XYZ can be converted to sRGB (using sRGB color primaries) with
>>> linear_rgb = dc.xyz2srgb(xyz)
>>> linear_rgb
array([0.99988402, 1.00003784, 0.99996664])
Because we have used a D65 specter data to compute the XYZ tristimulus values, the resulting RGB equals full brightness white color [1,1,1] (small deviation comes from the numerical precision of the XYZ2RGB color matrix transform). Note that Color matrices in the standard are defined for 8bit transformation. When converting float values to unsigned integer (8bit mode), these values have to be multiplied with 255 and clipped to a range of [0,255]. Finally, we have to apply the sRGB gamma curve to have this linear data ready to display on an sRGB monitor.
>>> rgb = dc.apply_srgb_gamma(linear_rgb)
Since conversion to sRGB color space (from the input specter values) is a standard operation, there is a helper function to perform this transformation in a single call:
>>> rgb2 = dc.specter2color(spec,cmf)
>>> np.allclose(rgb,rgb2)
True
Transmission CMF¶
We can define a transmission color matching function. The idea is to have the CMF function defined for transmission coefficients for a specific illumination. The transmission computation becomes independent of the actual light spectra used in the experiment. For example, say we have computed transmission coefficients for a given set of wavelengths
>>> wavelengths = [380,480,580,680,780]
>>> coefficients = [1,1,1,1,1]
We want to construct a color matching function that will convert these coefficients to color, assuming a given light spectrum. We can build a transmission color matching function with
>>> tcmf = dc.cmf2tcmf(cmf, spec)
or we could have loaded this directly with:
>>> tcmf2 = dc.load_tcmf()
>>> np.allclose(tcmf,tcmf2)
True

D65-normalized XYZ tristimulus values. (Source code, png, hires.png, pdf)¶
This way, we defined a new CMF function that converts unity transmission curve to bright white color (We are using D65 illuminant here).
>>> rgb3 = dc.specter2color([1]*81,tcmf)
>>> import numpy as np
>>> np.allclose(rgb,rgb3)
True
All fair, but we would not like to compute transmission coefficients at all 81 wavelengths defined in the original CMF data. We need to integrate the CMF function.
>>> itcmf = dc.integrate_data(wavelengths, np.linspace(380,780,81), tcmf)
which results in a new CMF function applicable to transmission coefficients defined at new (different) wavelengths.
We could have built this data directly by:
>>> itcmf = dc.load_tcmf(wavelengths)
Now we can compute
>>> rgb4 = dc.specter2color(coefficients,itcmf)
>>> import numpy as np
>>> np.allclose(rgb,rgb4)
True
Color Rendering¶
Not all colors can be displayed on an sRGB monitor. Colors that are out of gamut (R,G,B) channels are larger than 1. or smaller than 0. are clipped. For instance, a D65 light that gives (R,G,B) = (1,1,1)* intensity filtered with a 150 nm band-pass filter already has colors clipped at some higher intensities values. These colors are more vivid and saturated at a light intensity of 1.

An example of color rendering of a D65 illuminant filtered with a band-pass filter. If the illuminant is too bright, color clipping may occur. (Source code, png, hires.png, pdf)¶
Also, with sRGB color space we cannot render all colors, especially in the green part of the spectrum. For example, let us compute the RGB values of a D65 light filtered with a band-pass filter between 500 and 550 nm.
>>> tcmf = dc.load_tcmf([500,550])
>>> xyz = dc.spec2xyz([1.,1.], tcmf)
>>> rgb = dc.xyz2srgb(xyz)
>>> rgb
array([-0.37267476, 0.67704885, -0.0234957 ])
gives a strong negative value in the red channel, which shows that the color is too saturated to be displayed in an sRGB color space. After we apply gamma (which clips the RGB channels to (0,1.)) we get
>>> dc.apply_srgb_gamma(rgb)
array([0. , 0.84176254, 0. ])
with the blue and red channel clipped. We should have used wide-gamut color space and a monitor capable of displaying wider gamuts to properly display this color. As stated already, this package was not intended to be a full color management system, and you should use your own CMS system if you need more complex color transforms and rendering.
Color cameras¶
In simulations, light source is assumed to be the D65 illuminant by default. The reason is that with a D65 light source, the color of a fully transmissive filter is neutral gray (or white) when using the CIE color-matching functions. Suppose you want to compare with experiments, when using D65 light in simulation. In that case, you should do a proper white balance correction in your camera to obtain similar color rendering of the images obtained in experiments.
Another option is to match the illuminant used in the simulation to the illuminant used in the experiment.
>>> wavelengths = [510,550,590]
>>> illuminant =[[510,0],[530,0.8],[550,1],[570,0.8],[590,0]]
>>> cmf = dc.load_tcmf(wavelengths, illuminant = illuminant)
Here, the illuminant is a 2D table of intensity values of the source specified at given wavelengths (in nanometers). When calculating the transmittance color matching function we specify at which wavelengths we have calculated the transmittance (or reflectance). Generally, you should compute the transmittance/reflectance over a series of wavelengths that cover the bandwidth of the source. These need not to be the same wavelengths as the illuminant’s wavelengths. The load_tcmf function performs normalization and proper integration of the illuminant data.
If you have illuminant data stored in a file called “illuminant.dat”. You can create a cmf function by
>>> wavelengths = np.linspace(380,780,9)
>>> cmf = dc.load_tcmf(wavelengths, illuminant = "illuminant.dat")
or you can use one of the standard CIE illuminants, like the illuminant A:
>>> field, wavelengths, pixelsize = field_data
>>> cmf = dc.load_tcmf(wavelengths, illuminant = "A")
Afterward, it is possible to set this cmf in the field_viewer or pom_viewer.
>>> viewer = dtmm.pom_viewer(field_data, cmf = cmf)
For a standard A illuminant the example from the front page look like this:

A hello world example, but this time, illumination was performed with a standard A illuminant. (Source code, png, hires.png, pdf)¶
Now, to compare this with the experimentally obtained images, you should disable all white balance correction in your camera, or if your camera has this option, set the white balance to daylight conditions. This way, your color camera will transform the image assuming a D65 light source illuminant, just as the dtmm package does when it computes the RGB image. Also, non-scientific cameras typically use some standard color profiles that increase the saturation of colors. Probably it is best to use a neutral or faithful color profile if your camera provides you with this option.
If you use a color camera to capture monochrome images, you can simulate this with
>>> viewer = dtmm.pom_viewer(field_data, cmf = cmf, gray = True)
which tells the viewer that it should convert the RGB color to gray color. The actual conversion is done in XYZ color space and the resulting gray image is the Y channel of the XYZ color.
Monochrome cameras¶
To simulate a monochrome camera, you also have to construct a proper color matching function. For example, for a standard CMOS camera, to build a tcmf color matching function for light source approximated with three wavelengths and an illuminant specified by the illuminant table, do:
>>> wavelengths = (400,450,500)
>>> illuminant = [[400,0],[430,0.8],[450,1],[470,0.8],[500,0]]
>>> cmf = dtmm.color.load_tcmf(wavelengths,cmf = "CMOS",illuminant = illuminant)
If you have a custom spectral response function stored in a file, you can read that too with the above function. See the example below for details.

A hello world example, but this time, with a custom light source and a monochrome camera. (Source code, png, hires.png, pdf)¶
Configuration & Tips¶
In the dtmm.conf
there are a few configuration options that you can use for custom configuration, optimization and tuning. The package relies heavily on numba-optimized code. Default numba compilation options are used. For fine-tuning you can of course use custom compilation options that numba provides (See numba compilation options). There are also a few numba related environment variables that you can set in addition to numba compilation options. These are explained below.
Verbosity¶
By default compute functions do not print to stdout. You can set printing of progress bar and messages with:
>>> import dtmm
>>> dtmm.conf.set_verbose(1) #level 1 messages
0
>>> dtmm.conf.set_verbose(2) #level 2 messages (more info)
1
To disable verbosity, set verbose level to zero:
>>> dtmm.conf.set_verbose(0) #disable printing to stdout
2
Note
The setter functions in the dtmm.conf
module return previous defined setting.
Numba multithreading¶
Most computationally expensive numerical algorithms were implemented using @vectorize or @guvecgorize and can be compiled with target=”parallel” option. By default, parallel execution is disabled. You can enable parallel target for numba functions by setting the DTMM_TARGET_PARALLEL environment variable. This has to be set prior to importing the package.
>>> import os
>>> os.environ["DTMM_TARGET_PARALLEL"] = "1"
>>> import dtmm #parallel enabled dtmm
Another option is to modify the configuration file (see below). Depending on the number of cores in your system, you should be able to notice an increase in the computation speed.
To set the desired number of threads used in the calculation:
>>> dtmm.conf.set_numba_threads(2)
4
Numba cache¶
Numba allows caching of compiled functions. For debugging purposes, you can enable/disable caching with DTMM_NUMBA_CACHE environment variable. To disable caching (enabled by default):
>>> os.environ["DTMM_NUMBA_CACHE"] = "0"
To enable/disable caching you can modify the configuration file (see below). The cached files are stored in __pycache__ folder in the package’s root directory.
FFT optimization¶
The package was intended to work with mkl_fft or pyfftw FFT library. In stock numpy or spicy, there are no inplace FFT transform and FFT implementation is not optimized. Although the package works without the intel or fftw library, you are advised to install mkl_fft or pyfftw for best performance.
You can select FFT library (“mkl_fft”, “pyfftw”, “numpy”, or “scipy”) with the following:
>>> dtmm.conf.set_fftlib("mkl_fft")
'mkl_fft'
For mkl_fft and scipy there is an additional optimization step. Intel’s FFT implementation is multithreaded for single FFT computation, which works well for large sized arrays, but there is a very small increase in speed when computing smaller arrays (say 256x256 and smaller). In light transmission calculation, for each wavelength, each polarization, or ray direction there are four 2D FFT and four 2D IFFT computations performed per layer. Instead of parallelizing each of the transforms it is better to make all these transforms in parallel.
FFT functions in the dtmm.fft
can be parallelized using a ThreadPool. By default, this parallelization is disabled and you can enable ThreadPool parallelization of FFTs with:
>>> dtmm.conf.set_thread_pool(True)
False
Note
Creating a ThreadPool in python adds some overhead (a few miliseconds). It makes sense to perform multithreading if computational complexity is high enough. MKL’s threading works well for large arrays, but for large number of computations of small arrays, (as in multi-ray computations) ThreadPool should be faster.
You can also define number of threads used in fft. This number is independent of the number of threads used for numba-compiled functions.:
>>> dtmm.conf.set_fft_threads(4)
2
If you choose to use pyfftw, you can define fft planner effort with:
>>> dtmm.conf.set_fft_planner(2) #int 0-3
1
Which may find a faster version of fft. For pyfftw, the created FFTW plans are stored in dtmm.fft.FFTW_CACHE
. If you are running lots of computations on different fft sizes, you may be forced to clear resources to free memory:
>>> dtmm.fft.clear_cache()
After clearing the cache, pyfftw will have to prepare new plan for each new fft transform. Transform is new, if input and output arrays have different shape and stride parameters. If you call fft functions repeatedly with same input/output arrays fftw collects the plan from the cache, which speeds up the computation.
Default threading options can also be set in the configuration file (see below).
Precision¶
By default, computation is performed in double precision. You may disable double precision if you are low on memory, and to gain some speed in computation.
>>> os.environ["DTMM_DOUBLE_PRECISION"] = "0"
Please note that if you work with single precision you also have to prepare optical data and field data in single precision. You can also use fastmath option in numba compilation to gain some small speed by reducing the computation accuracy when using MKL.
>>> os.environ["DTMM_FASTMATH"] = "1"
Default values can also be set the configuration file (see below).
DTMM cache¶
DTMM package uses results cache internally. You can disable caching of results by:
>>> dtmm.conf.set_cache(0)
1
If you are running out of memory you should probably disable cashing. To clear cached data you can call:
>>> dtmm.conf.clear_cache()
Default option can also be set the configuration file (see below).
DTMM configuration file¶
You can also edit the configuration file .dtmm/dtmm.ini in user’s home directory to define default settings. This file is automatically generated from a template if it does not exist in the directory. To create the default configuration file, remove the configuration file and import the library in python.
[core]
#: verbose level (0,1 or 2)
verbose = 0
#: max beta parameter used in calculations. Should be 0 < betamax
betamax = 0.8
#: smoothnes parameter used in reflection calculation in 4x4 method Should be 0 < smooth
smooth = 0.1
#: specifies if computation results are being cached or not
cache = yes
#: specifies whether double precision is used in calculations:
double_precision = yes
[transfer]
#: default effective data 0 - isotropic, 1 - uniaxial, 2 - biaxial
eff_data = 0
#: default input refractive index. If not set or empty, defaults to n_cover.
#nin =
#: default output refractive index. If not set or empty, defaults to n_cover .
#nout =
#: either 2x2 or 4x4
method = "2x2"
#: how many passes to perform (set this to > 1) if you want to compute reflections also.
npass = 1
#: diffraction quality (0,1,2... or -1 for full diffraction).
diffraction = 1
#: reflection mode, either 0, 1 or 2 or comment out to let the algorithm choose the best mode
#reflection = 2
[viewer]
#: default cmf function or path to tabulated cmf data used in field_viewer.
cmf = CIE1931
#: specifies whether to show ticks or not, comment out or leave empty for auto.
#show_ticks =
#: specifies whether to show scale bar, you must have matplotlib.scale_bar installed.
show_scalebar = no
#: specifies whether to show sliders in the viewer.
show_sliders = yes
#: specified whether to convert RGB to gray.
gray = no
#: specifies whether to apply gamma or not, or set the gamma as float.
gamma = yes
#gamma = 2.
#: cover glass refractive index used in pom_viewer.
n_cover = 1.5
#: cover glass thickness. Set to zero or comment out to disable cover glass.
d_cover = 0.
#: specifies whether oil imersion microscope is being use or not.
immersion = no
#: numerical aperture of the objective. Should be lower than 1 for non-immersion objectives.
NA = 0.7
[numba]
#: are compiled numba functions cached or not.
cache = yes
#: should we compile with multithreading support ('target = parallel' option).
parallel = no
#: should numba use 'fastmath = True' option.
fastmath = no
#: number of threads used for numba-compiled functions. Uncomment it and set to desired value.
# number of threads (int) is defined automatically if not defined below.
#nthreads =
[fft]
#: fft library used for fft, can be mkl_fft, numpy, scipy, comment out to use default library.
#fftlib =
#: specifies whether we use python's threading for fft, or we leave it as implemented in the fft library.
#: setting this to yes disable threading in mkl_fft and scipy and uses Pool-based threading.
#: this parameter does not affect pyfftw threading. Defaults to 'no'.
#thread_pool = no
#: number of threads (int) used if parallel mode is activated. Uncomment it and set to desired value.
# number of threads is defined automatically if not defined below.
#nthreads =
Release Notes¶
V0.7.0 (May 25 2021)¶
This release improves multi-threading computation speed and adds several new features. It add support for pyfftw and matplotlib>=3.4.
New features¶
We introduce new optical data model. Legacy data model, which is in this version refered to as an optical block, is still a valid optical data. New optical data model is now a list of optical blocks. It is now possible to mix homogeneous layers with inhomogeneous layers and it simplifies creation of the optical stack.
New solver.py module with two objects for easier usage of non-iterative matrix-based simulations
New hybrid solver for heterogeneous data, which is triggered when create_matrix argument is set. See
dtmm.transfer.tranfer_field()
for details.Several new options for computation optimization in dtmm.ini. See the documentation for details.
Implements a new thread poll for parallel fft computation, which is faster than native threading in mkl_fft or scipy. This feature is still in beta, so it is disabled by defauly and you must activate it using a configuration file or using
dtmm.conf.set_thread_pool()
.Support for pyfftw. You can enable it by calling
dtmm.conf.set_fftlib()
with ‘pyfftw’ as an argument.New RangeSlider for condenser aperture setting, allowing you to set annular aperture in matplotlib figure (matplotlib 3.4 only).
Added an option to specify annular aperture in illumination_data and in the viewer’s aperture atrribute.
Fixes¶
Fixes BulkViewer (that got broken in 0.6 release).
Fixes CustomRadioButtons, which stopped working in matplotlib 3.4.
In mode grouping (When working with diffraction > 1) the effective beam parameter is now more accurately determined. The results using low diffraction e.g 2,3,4 are now more accurate.
When working with single precision, atol and rtol values are now less strict when checking for real eigenvector output in eps2epsva function.
Cached functions now support list argument.
When using numpy for fft and in single precision, ouput of fft2 is checked to be of correct type (“complex64”). In previous version this check was not made, resulting in a possible calculation error if the underlying fft2 implementation in numpy chose “complex128” as an otput.
Changes¶
New optical data format. In previous versions, optical data was a tuple of three elements. Now, optical data is a list of tuples. Each element in the list represents an optical block, which was called optical data in previous releases. Users should adopt the new optical data format in their code.
In previous versions, the :func:set_nthreads changed the number of fft threads and activated the thread pool. Now it changes number of threads used both for fft and numba computation, but it does not activate the thread pool. You must explicitly call dtmm.conf.set_thread_pool(True).
Drops support for older versions of numba. Minimum version of numba is now 0.45.0
Drops support for older versions of numpy. Minimum version of numpy is now 1.20
V0.6.1 (Nov 10 2020)¶
This is a bugfix release, focusing on documentation/examples improvements:
New jones caculus example.
Fixes¶
linalg.dot_multi now works with input matrices of different shapes
jones.jones_intensity now returns float instead of complex.
pom_viewer now correctly converts field to jones, assuming n_cover as the refractive index (instead of n - the output medium).
data.illumination_data now uses n = n_cover as the default medium (instead of n = 1).
V0.6.0 (Nov 6 2020)¶
This release adds many new features.
Please note that this release also partially breaks backward compatibility because of code refactoring. High-level functions remain backward compatible, but some low-level functions were renamed, omitted or replaced with a different implementation. See Changes for details.
New features¶
New
dtmm.field_viewer.pom_viewer()
for more accurate optical microscope simulations for experiments done with thick cover glass.Full support for tensorial input data handling (both for the Q tensor or for the eps tensor, real or complex valued epsilon).
RadioButtons for FieldViewer, with options for LCP and RCP polarizations and retardation settings (lambda/2 and lambda/4) plates.
Added show_scalebar option in FieldViewer.plot().
New CMOS spectral response function to allow simulations using grayscale cameras.
Simplified tcmf data generation for custom spectral data using load_tcmf and load_specter
New
dtmm.data.effective_data()
function to simplify effective data construction.The eff_data argument of
dtmm.transfer.transfer_field()
can now take strings “isotropic”, “uniaxial” or “biaxial” to simplify creation of effective medium.New jones4.py module for creation of 4x4 jones-like matrices to simplify polarization handling of field data.
Extended configuration options in dtmm.ini.
Changes¶
Removed tensor_to_matrix function fromm rotation.py, added tensor2matrix and matrix2tensor functions in data.py
Moved polarizer4x4 and jonesmat4x4 from tmm.py to jones4.py
Removed polarization.py in favor of jones4.py.
New defaults for transfer_field’s nin and nout arguments. These now default to the newly introduced n_cover parameter and a configuration parameter inside dtmm.ini. You can override this behavior by setting nin and not options in dtmm.ini file.
Removed the NUMBA_CACHE_DIR option in conf.py, which appears to fix the segfault error.
Fixes¶
segfault error due to numba caching.
V0.5.0 (Oct 20 2020)¶
Initial support for non-iterative 4x4 calculation with reflections (for 2d data)
V0.4.0 (May 22 2020)¶
Initial official release.
API Reference¶
This page contains auto-generated API reference documentation 1.
dtmm
¶
Diffractive transfer matrix method
Submodules¶
dtmm.color
¶
Color conversion functions and utilities.
CMF creation function¶
load_cmf()
: loads specter cmf data from file or pre-defined tableload_tcmf()
: loads transmission cmf data from file or pre-defined tablecmf2tcmf()
: converts cmf to transmission cmf.srf2cmf()
: converts spectral respone data to cmfload_specter()
: load specter from file or from data.normalize_specter()
: for specter normalization.
Color conversion¶
specter2color()
: converts specter data to color RGB or gray image.apply_gamma()
: applies gamma curve to linear dataapply_srgb_gamma()
: applies sRGB gamma curve to linear dataxyz2rgb()
: Converts XYZ data to RGBxyz2gray()
: Converts XYZ data to YYY (gray)spec2xyz()
: Converts specter to XYZ
Module Contents¶
-
dtmm.color.
apply_gamma
(value, gamma)¶ apply_gamma(value, gamma)
Applies standard gamma function (transfer function) to the given (linear) data.
- Parameters
value (float) – Input value
gamma (float) – Gamma factor
-
dtmm.color.
apply_srgb_gamma
(value)¶ apply_srgb_gamma(value)
Applies sRGB gamma function (transfer function) to the given (linear) data.
-
dtmm.color.
xyz2srgb
(xyz, rgb)¶ xyz2srgb(xyz)
Converts XYZ value to RGB value based on the sRGB working space with D65 reference white.
-
dtmm.color.
xyz2gray
(xyz, gray)¶ xyz2gray(xyz)
Converts XYZ value to Gray color
-
dtmm.color.
spec2xyz
(spec, cmf, xyz)¶ spec2xyz(spec,cmf)
Converts specter array to xyz value.
- Parameters
spec (array_like) – Input specter data
cmf (array_like) – Color matching function
- Returns
xyz – Computed xyz value.
- Return type
ndarray
-
dtmm.color.
specter2color
(spec, cmf, norm=False, gamma=True, gray=False, out=None)¶ Converts specter data to RGB data (color or gray).
Specter shape must be […,k], where wavelengths are in the last axis. cmf must be a valid color matchin function array of size [k,3].
- Parameters
spec (array) – Specter data of shape […, n] where each data element in the array has n wavelength values
cmf (array) – A color matching function (array of shape [n,3]) that converts the specter data to a XYZ color.
norm (bool or float, optional) – If set to False, no data normalization is performed (default). If True, internally, xyz data is normalized in the range [0,1.], so that no clipping occurs. If it is a float, data is normalized to this value.
gamma (bool or float, optional) – If gamma is True srgb gamma function is applied (default). If float is provided, standard gamma factor is applied with a given gamma value. If False, no gamma correction is performed.
gray (bool, optional) – Whether gray output is calculated (color by default)
out (array, optional) – Output array of shape (…,3)
- Returns
rgb – A computed RGB value.
- Return type
ndarray
Notes
Numpy broadcasting rules apply to spec and cmf.
Example
>>> cmf = load_tcmf() >>> specter2color([1]*81, cmf)#should be close to 1,1,1 ... array([0.99994901, 1. , 0.99998533])
-
dtmm.color.
srf2cmf
(srf, out=None)¶ Converts spectral response function (Y) to color matching function (XYZ).
- Parameters
srff (array_like) – Spectral response function of shape (…,n)
out (ndarray, optional) – Output array.
- Returns
cmf – A color matching function array of shape (…,n,3)
- Return type
ndarray
-
dtmm.color.
normalize_specter
(spec, cmf, out=None)¶ Normalizes specter based on the color matching function. (cmf array) so that calculated Y value is 1.
- Parameters
spec (array_like) – Input illuminant specter data of shape (…,n).
cmf (array_like) – Color matching function of shape (…,n,3).
out (ndarray, optional) – Output array.
- Returns
normalized_spec – A normalized version of the input specter
- Return type
ndarray
Notes
Numpy broadcasting rules apply to spec and cmf.
-
dtmm.color.
load_tcmf
(wavelengths=None, illuminant='D65', cmf=CMF, norm=True, retx=False, single_wavelength=False)¶ Loads transmission color matching function.
This functions loads a CIE XYZ color matching function and transforms it to a transmission color matching function for a given illuminant. Resulting CMF matrix will transform unity into white color.
- Parameters
wavelengths (array_like, optional) – Wavelengths at which data is computed. If not specified (default), original data from the 5nm tabulated data is returned.
illuminant (str, optional) – Name of the standard illuminant or path to illuminant data.
cmf (str, optional) – Name or path to the cmf function. Can be ‘CIE1931’ for CIE 1931 2-deg 5nm tabulated data, ‘CIE1964’ for CIE1964 10-deg 5nm tabulatd data, or ‘CIE2006-2’ or ‘CIE2006-10’ for a proposed CIE 2006 2- or 10-deg 5nm tabulated data.
norm (int, optional) – By default cmf is normalized so that unity transmission value over the full spectral range of the illuminant is converted to XYZ color with Y=1. You can disable this by setting norm = 0. If you set norm = 2, then the cmf is normalized for the interpolated spectra at given wavelengths, and not to the full bandwidth of the spectra (norm = 1).
retx (bool, optional) – Should the selected wavelengths be returned as well.
single_wavelength (bool, optional) – If specified, color matching function for single wavelengths specter is calculated by interpolation. By default, specter is assumed to be a piece-wise linear function and continuous between the specified wavelengts, and data is integrated instead.
- Returns
cmf – Color matching function array of shape [n,3] or a tuple of (x,cmf) if retx is specified.
- Return type
array
Example
>>> cmf = load_tcmf() >>> specter2color([1]*81, cmf) #should be close to 1,1,1 ... array([0.99994901, 1. , 0.99998533])
-
dtmm.color.
cmf2tcmf
(cmf, spec, norm=True, out=None)¶ Converts CMF table to specter-normalized transmission CMF table
- Parameters
cmf (array_like) – Color matchinf function array
spec (array_like) – Illuminant specter array
norm (bool, optional) – Whether to normalize illuminant specter before constructing the CMF.
out (ndarray, optional) – Output array
- Returns
out – A transmission color matching function array.
- Return type
ndarray
Notes
Numpy broadcasting rules apply to spec and cmf.
-
dtmm.color.
load_specter
(wavelengths=None, illuminant='D65', retx=False)¶ Loads illuminant specter data from file.
- Parameters
wavelengths (array_like, optional) – Wavelengths at which data is interpolated
illuminant (str, or array, optional) – Name of the standard illuminant or filename. If specified as array, it must be an array of shape (n,2). The first column decribes wavelength and the second is the intensity.
retx (bool, optional) – Should the selected wavelengths be returned as well.
- Returns
specter – Specter array of shape [num] or a tuple of (x,specter) if retx is specified
- Return type
array
Example
#D65 evaluated at three wavelengths >>> spec = load_specter((450,500,550), “D65”)
#illuminant with triangular specter evaluated at three wavelengths >>> spec = load_specter([450,475,500,], illuminant = [[400,0],[500,1],[600,0]])
-
dtmm.color.
load_cmf
(wavelengths=None, cmf=CMF, retx=False, single_wavelength=False)¶ Load XYZ Color Matching function.
This function loads tabulated data and re-calculates xyz array on a given range of wavelength values.
See also load_tcmf.
- Parameters
wavelengths (array_like, optional) – A 1D array of wavelengths at which data is computed. If not specified (default), original data from the 5nm tabulated data is returned.
cmf (str, optional) – Name or path to the cmf function. Can be ‘CIE1931’ for CIE 1931 2-deg 5nm tabulated data, ‘CIE1964’ for CIE1964 10-deg 5nm tabulated data, or ‘CIE2006-2’ or ‘CIE2006-10’ for a proposed CIE 2006 2- or 10-deg 5nm tabulated data. For grayscale cameras, there is a ‘CMOS’ spectral response data. You can also provide ‘FLAT’ for flat (unity) response function.
retx (bool, optional) – Should the selected wavelengths be returned as well.
single_wavelength (bool, optional) – If specified, color matching function for single wavelengths specter is calculated by interpolation. By default, specter is assumed to be a piece-wise linear function and continuous between the specified wavelengts, and data is integrated instead.
- Returns
cmf – Color matching function array of shape [n,3] or a tuple of (x,cmf) if retx is specified.
- Return type
array
-
dtmm.color.
interpolate_data
(x, x0, data)¶ Interpolates data
- Parameters
x (array_like) – The x-coordinates at which to evaluate the interpolated values.
x0 (array_like) – The x-coordinates of the data points, must be increasing.
data (ndarray) – A 1D or 2D array of datapoints to interpolate.
- Returns
y – The interpolated values.
- Return type
ndarray
-
dtmm.color.
integrate_data
(x, x0, cmf)¶ Integrates data.
This function takes the original data and computes new data at specified x coordinates by a weighted integration of the original data. For each new x value, it multiplies the data with a triangular kernel and integrates. The width of the kernel is computed from the spacings in x.
- Parameters
x (array_like) – The x-coordinates at which to compute the integrated data.
x0 (array_like) – The x-coordinates of the data points, must be increasing.
data (ndarray) – A 1D or 2D array of datapoints to integrate.
- Returns
y – The integrated values.
- Return type
ndarray
dtmm.conf
¶
dtmm configuration functions and constants
Module Contents¶
-
dtmm.conf.
get_home_dir
()¶ Return user home directory
-
dtmm.conf.
is_module_installed
(name)¶ Checks whether module with name ‘name’ is istalled or not
-
dtmm.conf.
clear_cache
(func=None)¶ Clears compute cache.
- Parameters
func (function) – A cached function of which cache results are to be cleared (removed from cache). If not provided (default) all cache data is cleared from all registred cached function - functions returned by the
cached_function()
decorator
-
dtmm.conf.
cached_function
(f)¶ A decorator that converts a function into a cached function.
The function needs to be a function that returns a numpy array as a result. This result is then cached and future function calls with same arguments return result from the cache. Function arguments must all be hashable, or are small numpy arrays. The function can also take “out” keyword argument for an output array in which the resulting array is copied to.
Notes
When caching is enabled, cached numpy arrayes have a read-only attribute. You need to copy first, or provide an output array if you need to write to the result.
-
dtmm.conf.
cached_result
(f)¶ A decorator that converts a function into a cached result function.
The function needs to be a function that returns any result. Function arguments must all be hashable, or are small numpy arrays.
-
dtmm.conf.
detect_number_of_cores
()¶ detect_number_of_cores()
Detect the number of cores in this system.
- Returns
out – The number of cores in this system.
- Return type
int
-
dtmm.conf.
disable_mkl_threading
()¶ Disables mkl threading.
-
dtmm.conf.
enable_mkl_threading
()¶ Enables mkl threading.
-
class
dtmm.conf.
DTMMConfig
¶ Bases:
object
DTMM settings are here. You should use the set_* functions in the conf.py module to set these values
-
dtmm.conf.
get_default_config_option
(name, value=None)¶ Returns default config option specified with ‘name’, if value is not None, returns value instead
-
dtmm.conf.
print_config
()¶ Prints all compile-time and run-time configurtion parameters and settings.
-
dtmm.conf.
set_verbose
(level)¶ Sets verbose level (0-2) used by compute functions.
-
dtmm.conf.
set_cache
(level)¶ Sets compute cache level.
-
dtmm.conf.
set_fftlib
(name='numpy.fft')¶ Sets fft library name.
-
dtmm.conf.
set_betamax
(value)¶ Sets betamax value.
-
dtmm.conf.
set_fft_threads
(n)¶ Sets number of threads used in fft functions.
-
dtmm.conf.
set_fft_planner
(n)¶ Sets fft planner effort (pyfftw) 0-3, higher means more planning effort
-
dtmm.conf.
set_thread_pool
(ok)¶ Sets or unsets ThreadPool. If set to True, a ThreadPoll is used for threading. If set to False, threading is defined by the fft library.
-
dtmm.conf.
set_numba_threads
(n)¶ Sets number of threads used in numba-accelerated functions.
-
dtmm.conf.
set_nthreads
(num)¶ Sets number of threads used by numba and fft functions.
dtmm.data
¶
Director and optical data creation and IO functions.
Conversion functions¶
director2data()
generates optical block data from director.Q2data()
generates optical block data from the Q tensor.director2order()
computes order parameter from directo length.director2Q()
computes uniaxial Q tensor.Q2director()
computes an effective uniaxial director from a biaxial Q tensor.director2angles()
computes Euler rotation angles from the director.angles2director()
computes the director from Euler rotation angles.Q2eps()
converts Q tensor to epsilon tensor.eps2epsva()
converts epsilon tensor to epsilon eigenvalues and Euler angles.epsva2eps()
converts epsilon eigenvalues and Euler angles to epsilon tensor.tensor2matrix()
convert tensor to matrix.matrix2tensor()
convert matrix to tensor.refind2eps()
convert refractive index eigenvalues to epsilon eigenvalues.uniaxial_order()
creates uniaxial tensor from a biaxial eigenvalues.sellmeier2eps()
computes epsilon from Sellmeier coefficients.cauchy2eps()
computes epsilon from Cauchy coefficients.
IO functions¶
read_director()
reads 3D director data.read_tensor()
reads 3D tensor data.read_raw()
reads any raw data.load_stack()
loads optical data.save_stack()
saves optical data.
Data creation¶
validate_optical_block()
validates data.validate_optical_data()
validates data.evaluate_optical_block()
evaluates data.evaluate_optical_data()
evaluates data.eig_symmetry()
creates effective tensor of given symmetry.effective_block()
computes effective (mean layers) 1D data from 3D data.effective_data()
computes effective (mean layers) 1D data from 3D data.split_block()
Splits block data into layersed datalayerd_data()
Splits optical data into layered data.
Utilities and sample data¶
nematic_droplet_data()
builds sample data.nematic_droplet_director()
builds sample director.cholesteric_droplet_data()
builds sample data.cholesteric_director()
builds sample director.expand()
expands director data.sphere_mask()
builds a masking array.rot90_director()
rotates director by 90 degreesrotate_director()
rotates data by any angle
Module Contents¶
-
dtmm.data.
read_director
(file, shape, dtype=FDTYPE, sep='', endian=sys.byteorder, order='zyxn', nvec='xyz')¶ Reads raw director data from a binary or text file.
A convinient way to read director data from file.
- Parameters
file (str or file) – Open file object or filename.
shape (sequence of ints) – Shape of the data array, e.g.,
(50, 24, 34, 3)
dtype (data-type) – Data type of the raw data. It is used to determine the size of the items in the file.
sep (str) – Separator between items if file is a text file. Empty (“”) separator means the file should be treated as binary. Spaces (” “) in the separator match zero or more whitespace characters. A separator consisting only of spaces must match at least one whitespace.
endian (str, optional) – Endianess of the data in file, e.g. ‘little’ or ‘big’. If endian is specified and it is different than sys.endian, data is byteswapped. By default no byteswapping is done.
order (str, optional) – Data order. It can be any permutation of ‘xyzn’. Defaults to ‘zyxn’. It describes what are the meaning of axes in data.
nvec (str, optional) – Order of the director data coordinates. Any permutation of ‘x’, ‘y’ and ‘z’, e.g. ‘yxz’, ‘zxy’ …
-
dtmm.data.
read_tensor
(file, shape, dtype=FDTYPE, sep='', endian=sys.byteorder, order='zyxn')¶ Reads raw tensor data from a binary or text file.
A convinient way to read tensor data from file.
- Parameters
file (str or file) – Open file object or filename.
shape (sequence of ints) – Shape of the data array, e.g.,
(50, 24, 34, 6)
dtype (data-type) – Data type of the raw data. It is used to determine the size of the items in the file.
sep (str) – Separator between items if file is a text file. Empty (“”) separator means the file should be treated as binary. Spaces (” “) in the separator match zero or more whitespace characters. A separator consisting only of spaces must match at least one whitespace.
endian (str, optional) – Endianess of the data in file, e.g. ‘little’ or ‘big’. If endian is specified and it is different than sys.endian, data is byteswapped. By default no byteswapping is done.
order (str, optional) – Data order. It can be any permutation of ‘xyzn’. Defaults to ‘zyxn’. It describes what are the meaning of axes in data.
-
dtmm.data.
rotate_director
(rmat, data, method='linear', fill_value=(0.0, 0.0, 0.0), norm=True, out=None)¶ Rotate a director field around the center of the compute box by a specified rotation matrix. This rotation is lossy, as datapoints are interpolated. The shape of the output remains the same.
- Parameters
rmat (array_like) – A 3x3 rotation matrix.
data (array_like) – Array specifying director field with ndim = 4
method (str) – Interpolation method “linear” or “nearest”
fill_value (numbers, optional) – If provided, the values (length 3 vector) to use for points outside of the interpolation domain. Defaults to (0.,0.,0.).
norm (bool,) – Whether to normalize the length of the director to 1. after rotation (interpolation) is performed. Because of interpolation error, the length of the director changes slightly, and this options adds a constant length constraint to reduce the error.
out (ndarray, optional) – Output array.
- Returns
y – A rotated director field
- Return type
ndarray
See also
data.rot90_director
a lossless rotation by 90 degrees.
-
dtmm.data.
rot90_director
(data, axis='+x', out=None)¶ Rotate a director field by 90 degrees around the specified axis.
- Parameters
data (array_like) – Array specifying director field with ndim = 4.
axis (str) – Axis around which to perform rotation. Can be in the form of ‘[s][n]X’ where the optional parameter ‘s’ can be “+” or “-” decribing the sign of rotation. [n] is an integer describing number of rotations to perform, and ‘X’ is one of ‘x’, ‘y’ ‘z’, and defines rotation axis.
out (ndarray, optional) – Output array.
- Returns
y – A rotated director field
- Return type
ndarray
See also
data.rotate_director
a general rotation for arbitrary angle.
-
dtmm.data.
director2data
(director, mask=None, no=1.5, ne=1.6, nhost=None, scale_factor=1.0, thickness=None)¶ Builds optical block data from director data. Director length is treated as an order parameter. Order parameter of S=1 means that refractive indices no and ne are set as the material parameters. With S!=1, a
uniaxial_order()
is used to calculate actual material parameters.- Parameters
director (ndarray) – A 4D array describing the director
mask (ndarray, optional) – If provided, this mask must be a 3D bolean mask that define voxels where nematic is present. This mask is used to define the nematic part of the sample. Volume not defined by the mask is treated as a host material. If mask is not provided, all data points are treated as a director.
no (float) – Ordinary refractive index
ne (float) – Extraordinary refractive index
nhost (float) – Host refracitve index (if mask is provided)
scale_factor (float) – The order parameter S obtained from the director length is scaled by this factor. Optical anisotropy is then epsa = S/scale_factor * (epse - epso).
thickness (ndarray) – Thickness of layers (in pixels). If not provided, this defaults to ones.
- Returns
optical_data – A valid optical data tuple.
- Return type
tuple
-
dtmm.data.
Q2data
(tensor, mask=None, no=1.5, ne=1.6, nhost=None, scale_factor=1.0, biaxial=False, thickness=None)¶ Builds optical block data from Q tensor data.
- Parameters
tensor ((..,6) or (..,3,3) array) – Q tensor with elements Q[0,0], Q[1,1], Q[2,2], Q[0,1], Q[0,2], Q[1,2]
mask (ndarray, optional) – If provided, this mask must be a 3D bolean mask that define voxels where nematic is present. This mask is used to define the nematic part of the sample. Volume not defined by the mask is treated as a host material. If mask is not provided, all data points are treated as a director.
no (float) – Ordinary refractive index (when biaxial = False)
ne (float) – Extraordinary refractive index (when biaxial = False)
nhost (float) – Host refracitve index (if mask is provided)
scale_factor (float) – The order parameter S obtained from the Q tensor is scaled by this factor. Optical anisotropy is then epsa = S/scale_factor *(epse - epso).
biaxial (bool) – Describes whether data is treated as biaxial or converted to uniaxial (default). If biaxial, no describes the mean value of n1 and n2 refractive indices eigenavalues and ne = n3.
thickness (ndarray, optional) – Thickness of layers (in pixels). If not provided, this defaults to ones.
- Returns
optical_data – A valid optical data list.
- Return type
list
-
dtmm.data.
director2Q
(director, order=1.0)¶ Computes Q tensor form the uniaxial director.
- Parameters
director ((..,3) array) – Director vector. The length of the vector is the square of the order parameter.
order (float, optional) – In case director is normalized, this describes the order parameter.
- Returns
Q – Q tensor with elements Q[0,0], Q[1,1], Q[2,2], Q[0,1], Q[0,2], Q[1,2]
- Return type
(..,6) array
-
dtmm.data.
Q2director
(tensor, qlength=False)¶ Computes the director from tensor data
- Parameters
tensor ((..,6) or (..,3,3) array) – Tensor data.
qlength (bool) – Specifies whether the length of the director is set to the S parameter or not. If not, director is scalled to unity length.
- Returns
Q – Q tensor with elements Q[0,0], Q[1,1], Q[2,2], Q[0,1], Q[0,2], Q[1,2]
- Return type
(..,6) array
-
dtmm.data.
Q2eps
(tensor, no=1.5, ne=1.6, scale_factor=1.0, out=None)¶ Converts Q tensor to epsilon tensor
- Parameters
tensor ((..,6) or (..,3,3) ndarray) – A 4D array describing the Q tensor. If provided as a matrix, rhe elemnents are Q[0,0], Q[1,1], Q[2,2], Q[0,1], Q[0,2], Q[1,2]
no (float) – Ordinary refractive index when S = 1/scale_factor.
ne (float) – Extraordinary refractive index when S = 1/scale_factor.
scale_factor (float) – The order parameter S obtained from the Q tensor is scaled by this factor. Optical anisotropy is then epsa = S/scale_factor * (epse - epso).
out (ndarray, optional) – Output array
- Returns
eps – Calculated epsilon tensor.
- Return type
ndarray
-
dtmm.data.
eps2epsva
(eps)¶ Computes epsilon eigenvalues (epsv) and rotation angles (epsa) from epsilon tensor of shape (…,6) or represented as a (…,3,3)
- Parameters
eps ((..,3,3) or (..,6) array) – Epsilon tensor. If provided as a (3,3) matrix, the elements are eps[0,0], eps[1,1], eps[2,2], eps[0,1], eps[0,2], eps[1,2]
- Returns
epsv, epsa – Eigenvalues and Euler angles arrays.
- Return type
ndarray, ndarray
-
dtmm.data.
epsva2eps
(epsv, epsa)¶ Computes epsilon from eigenvalues (epsv) and rotation angles (epsa)
- Parameters
epsv ((..,3) array) – Epsilon eigenvalues array.
epsa ((..,3) array) – Euler angles array.
- Returns
eps – Epsilon tensor arrays of shape (…,6). The elements are eps[0,0], eps[1,1], eps[2,2], eps[0,1], eps[0,2], eps[1,2]
- Return type
ndarray
-
dtmm.data.
validate_optical_layer
(data, shape=None, wavelength=None, broadcast=False, copy=False)¶ Convenience function. See validate_optical_block for details.
Calls validate_optical_block with single_layer = True
-
dtmm.data.
validate_optical_block
(data, shape=None, wavelength=None, broadcast=False, copy=False, homogeneous=None, single_layer=False)¶ Validates optical block.
This function inspects validity of the optical block data, and makes proper data conversions to match the optical block format. In case data is not valid and it cannot be converted to a valid block data it raises an exception (ValueError).
- Parameters
data (tuple or list of tuples) – An optical data: either a single optical block tuple, or a list of block tuples.
shape ((int,int)) – If defined input epsilon tensor shape (eps.shape[:-1]) is checked to be broadcastable with the given shape.
wavelength (float) – Wavelength in nanometers at which to compute epsilon, in case epsv is a callable function.
broadcast (bool, optional) – Ehether to actually perform broadcasting of arrays. If set to False, only tests whether arrays can broadcast to a common shape, but no broadcasting is made.
copy (bool, optional) – Whether to copy data. If not set, (broadcasted) view of the input arrays is returned.
single_layer (bool) – If set to True, input data has to be a single layer data. Validated data is not converted to optical block of length 1.
- Returns
data – Validated optical block tuple.
- Return type
tuple
-
dtmm.data.
validate_optical_data
(data, shape=None, wavelength=None, broadcast=False, copy=False, homogeneous=None)¶ Validates optical data.
This function inspects validity of the optical data, and makes proper data conversions to match the optical data format. In case data is not valid and it cannot be converted to a valid optical data it raises an exception (ValueError).
- Parameters
data (tuple or list of tuples) – An optical data: either a single optical block tuple, or a list of block tuples.
shape ((int,int)) – Each block’s epsilon tensor shape (eps.shape[:-1]) is checked to be broadcastable with the given shape.
wavelength (float) – Wavelength in nanometers at which to compute epsilon, in case epsv is a callable function.
broadcast (bool, optional) – Ehether to actually perform broadcasting of arrays. If set to False, only tests whether arrays can broadcast to a common shape, but no broadcasting is made.
copy (bool, optional) – Whether to copy data. If not set, (broadcasted) view of the input arrays is returned.
- Returns
data – Validated optical data list.
- Return type
list of tuples
-
dtmm.data.
evaluate_optical_block
(optical_block, wavelength=550)¶ In case of dispersive material. This function evaluates and returns optical block at a given wavelength
-
dtmm.data.
evaluate_optical_data
(optical_data, wavelength=550)¶ In case of dispersive material. This function evaluates and return optical data at a given wavelength
-
dtmm.data.
raw2director
(data, order='zyxn', nvec='xyz')¶ Converts raw data to director array.
- Parameters
data (array) – Data array
order (str, optional) – Data order. It can be any permutation of ‘xyzn’. Defaults to ‘zyxn’. It describes what are the meaning of axes in data.
nvec (str, optional) – Order of the director data coordinates. Any permutation of ‘x’, ‘y’ and ‘z’, e.g. ‘yxz’, ‘zxy’. Defaults to ‘xyz’
- Returns
director – A new array or same array (if no trasposing and data copying was made)
- Return type
array
Example
>>> a = np.random.randn(10,11,12,3) >>> director = raw2director(a, "xyzn")
-
dtmm.data.
read_raw
(file, shape, dtype, sep='', endian=sys.byteorder)¶ Reads raw data from a binary or text file.
- Parameters
file (str or file) – Open file object or filename.
shape (sequence of ints) – Shape of the data array, e.g.,
(50, 24, 34, 3)
dtype (data-type) – Data type of the raw data. It is used to determine the size of the items in the file.
sep (str) – Separator between items if file is a text file. Empty (“”) separator means the file should be treated as binary. Spaces (” “) in the separator match zero or more whitespace characters. A separator consisting only of spaces must match at least one whitespace.
endian (str, optional) – Endianess of the data in file, e.g. ‘little’ or ‘big’. If endian is specified and it is different than sys.endian, data is byteswapped. By default no byteswapping is done.
-
dtmm.data.
sphere_mask
(shape, radius, offset=(0, 0, 0))¶ Returns a bool mask array that defines a sphere.
The resulting bool array will have ones (True) insede the sphere and zeros (False) outside of the sphere that is centered in the compute box center.
- Parameters
shape ((int,int,int)) – A tuple of (nlayers, height, width) defining the bounding box of the sphere.
radius (int) – Radius of the sphere in pixels.
offset ((int, int, int), optional) – Offset of the sphere from the center of the bounding box. The coordinates are (x,y,z).
- Returns
out – Bool array defining the sphere.
- Return type
array
-
dtmm.data.
nematic_droplet_director
(shape, radius, profile='r', retmask=False)¶ Returns nematic director data of a nematic droplet with a given radius.
- Parameters
shape (tuple) – (nz,nx,ny) shape of the output data box. First dimension is the number of layers, second and third are the x and y dimensions of the box.
radius (float) – radius of the droplet.
profile (str, optional) – Director profile type. It can be a radial profile “r”, or homeotropic profile with director orientation specified with the parameter “x”, “y”, or “z”, or as a director tuple e.g. (np.sin(0.2),0,np.cos(0.2)). Note that director length defines order parameter (S=1 for this example).
retmask (bool, optional) – Whether to output mask data as well
- Returns
out – A director data array, or tuple of director mask and director data arrays.
- Return type
array or tuple of arrays
-
dtmm.data.
cholesteric_director
(shape, pitch, hand='left')¶ Returns a cholesteric director data.
- Parameters
shape (tuple) – (nz,nx,ny) shape of the output data box. First dimension is the number of layers, second and third are the x and y dimensions of the box.
pitch (float) – Cholesteric pitch in pixel units.
hand (str, optional) – Handedness of the pitch; either ‘left’ (default) or ‘right’
- Returns
out – A director data array
- Return type
ndarray
-
dtmm.data.
nematic_droplet_data
(shape, radius, profile='r', no=1.5, ne=1.6, nhost=1.5)¶ Returns nematic droplet optical block data.
This function returns a thickness, material_eps, angles, info tuple of a nematic droplet, suitable for light propagation calculation tests.
- Parameters
shape (tuple) – (nz,nx,ny) shape of the stack. First dimension is the number of layers, second and third are the x and y dimensions of the compute box.
radius (float) – radius of the droplet.
profile (str, optional) – Director profile type. It can be a radial profile “r”, or homeotropic profile with director orientation specified with the parameter “x”, “y”, or “z”.
no (float, optional) – Ordinary refractive index of the material (1.5 by default)
ne (float, optional) – Extraordinary refractive index (1.6 by default)
nhost (float, optional) – Host material refractive index (1.5 by default)
- Returns
out – A (thickness, material_eps, angles) tuple of three arrays
- Return type
tuple of length 3
-
dtmm.data.
cholesteric_droplet_data
(shape, radius, pitch, hand='left', no=1.5, ne=1.6, nhost=1.5)¶ Returns cholesteric droplet optical block.
This function returns a thickness, material_eps, angles, info tuple of a cholesteric droplet, suitable for light propagation calculation tests.
- Parameters
shape (tuple) – (nz,nx,ny) shape of the stack. First dimension is the number of layers, second and third are the x and y dimensions of the compute box.
radius (float) – radius of the droplet.
pitch (float) – Cholesteric pitch in pixel units.
hand (str, optional) – Handedness of the pitch; either ‘left’ (default) or ‘right’
no (float, optional) – Ordinary refractive index of the material (1.5 by default)
ne (float, optional) – Extraordinary refractive index (1.6 by default)
nhost (float, optional) – Host material refractive index (1.5 by default)
- Returns
out – A (thickness, material_eps, angles) tuple of three arrays
- Return type
tuple of length 3
-
dtmm.data.
director2order
(data, out)¶ Converts director data to order parameter (square root of the length of the director)
-
dtmm.data.
director2angles
(data, out)¶ Converts director data to angles (yaw, theta phi)
-
dtmm.data.
angles2director
(data, out)¶ Converts angles data (yaw,theta,phi) to director (nx,ny,nz)
-
dtmm.data.
expand
(data, shape, xoff=None, yoff=None, zoff=None, fill_value=0.0)¶ Creates a new scalar or vector field data with an expanded volume. Missing data points are filled with fill_value. Output data shape must be larger than the original data.
- Parameters
data (array_like) – Input vector or scalar field data
shape (array_like) – A scalar or length 3 vector that defines the volume of the output data
xoff (int, optional) – Data offset value in the x direction. If provided, original data is copied to new data starting at this offset value. If not provided, data is copied symmetrically (default).
yoff – Data offset value in the x direction.
int – Data offset value in the x direction.
optional – Data offset value in the x direction.
zoff – Data offset value in the z direction.
int – Data offset value in the z direction.
optional – Data offset value in the z direction.
fill_value (array_like) – A length 3 vector of default values for the border volume data points.
- Returns
y – Expanded ouput data
- Return type
array_like
-
dtmm.data.
refind2eps
(refind)¶ Converts refractive index to epsilon
-
dtmm.data.
sellmeier2eps
(coeff, wavelength, out)¶ Converts Sellmeier coefficents to epsilon
Sellmeier formula is:
eps = A + sum_i B_i * w**2 / (w**2 - C_i)
where A = coeff[0], B_1 = coeff[1], C_1 = coeff[2], … and w is wavelength in microns.
Input coefficients array must be of odd length. How many elements (n) are there in the teries expansion of the Sellmeier formula depends on the length of the input coefficients n = (len(coeff)-1)//2
-
dtmm.data.
cauchy2eps
(coeff, wavelength, out)¶ Converts Cauchy coefficents to epsilon
Cauchy formula is
n = A + sum_i B_i / (w**(2*i)
where sumation is from i = 1 to imax = len(coeff)-1 A = coeff[0], B_1 = coeff[1], B_2 = coeff[2], … and w is wavelength in microns.
-
dtmm.data.
is_optical_block_dispersive
(optical_block)¶ inspectes whether optical block is dispersive or not
-
dtmm.data.
is_optical_data_dispersive
(optical_data)¶ inspectes whether optical data is dispersive or not
-
class
dtmm.data.
EpsilonDispersive
(values=None, shape=None, n=None, broadcast=False, copy=False)¶ Bases:
object
Base class for all dispersive material classes.
-
class
dtmm.data.
EpsilonCauchy
(values=None, shape=None, n=None, broadcast=False, copy=False)¶ Bases:
EpsilonDispersive
A callable epsilon tensor described with Cauchy coefficients
n = c[0] + c[1]/w**2 + c[2]/w**2 + … eps = n**2
where are c is the coefficient vector and w is wavelength in microns.
-
class
dtmm.data.
EpsilonSellmeier
¶ Bases:
object
A callable epsilon tensor described with Sellmeier coefficients.
eps = c[0] + w**2 * c[1] / (w**2 - c[2]) + w**2 * c[3] / (w**2 - c[4]) + …
where are c is the coefficient vector and w is wavelength in microns.
-
dtmm.data.
is_callable
(func)¶ Determines if func is a callable function or not
-
dtmm.data.
uniaxial_order
(order, eig, out)¶ uniaxial_order(order, eps)
Calculates uniaxial (or isotropic) eigen tensor from a diagonal biaxial eigen tensor.
- Parameters
order (float) – The order parameter. 1.: uniaxial, 0.: isotropic. If order is negative no change is made (biaxial case).
eig (array) – Array of shape (…,3), the eigenvalues. The eigenvalue [2] is treated as the extraordinary axis for the uniaxial order.
out (ndarray, optional) – Output array.
- Returns
out – Effective eigenvalues based on the provided symmetry (order) argument
- Return type
ndarray
Examples
>>> np.allclose(uniaxial_order(0,[1,2,3.]) , (2,2,2)) True >>> np.allclose(uniaxial_order(1,[1,2,3.]), (1.5,1.5,3)) True >>> np.allclose(uniaxial_order(-1,[1,2,3.]), (1,2,3)) #negative, so no change True >>> np.allclose(uniaxial_order(0.5,[1,2,3.]), (1.75,1.75,2.5)) #scale accordingly True
-
dtmm.data.
eig_symmetry
(order, eig, out=None)¶ Takes the ordered diagonal values of the tensor and converts it to uniaxial or isotropic tensor, or keeps it as biaxial.
Broadcasting rules apply.
- Parameters
order (int or array) – Integer describing the symmetry 0 : isotropic, 1 : uniaxial, 2 : biaxial. If specified as an array it mast be broadcastable. See
uniaxial_order()
.eig (array) – Array of shape (…,3), the eigenvalues. The eigenvalue [2] is treated as the extraordinary axis for the uniaxial order.
out (ndarray, optional) – Output array.
- Returns
out – Effective eigenvalues based on the provided symmetry (order) argument
- Return type
ndarray
See also
-
dtmm.data.
effective_block
(optical_block, symmetry=0, broadcast=True)¶ Builds effective block from the optical_block.
The material epsilon is averaged over the layers.
- Parameters
optical_block (tuple) – A valid optical block tuple.
symmetry (str, int or array) – Either ‘isotropic’ or 0, ‘uniaxial’ or 1 or ‘biaxial’ or 2 . Defines the symmetry of the effective layer. When set to ‘isotropic’, the averaging is done so that the effective layer tensor is isotropic. When set to ‘uniaxial’ the effective layer tensor is an uniaxial medium. If it is an array, it defines the symmetry of each individual layers independetly.
broadcast (bool, optional) – If set to True, output is assured to be broadcastable with optical_block elements.
- Returns
out – A valid optical block tuple of the effective layers.
- Return type
tuple
-
dtmm.data.
effective_data
(optical_data, symmetry=0)¶ Builds effective data from the optical_data.
The material epsilon is averaged over the layers.
- Parameters
optical_data (list) – A valid optical data list .
symmetry (str, int, or list) – Either ‘isotropic’ or 0, ‘uniaxial’ or 1 or ‘biaxial’ or 2 . Defines the symmetry of the effective layer. When set to ‘isotropic’, the averaging is done so that the effective layer tensor is isotropic. When set to ‘uniaxial’ the effective layer tensor is an uniaxial medium. If it is a list, it defines the symmetry of each individual block of data.
- Returns
out – A valid optical data of the effective layer blocks.
- Return type
list
-
dtmm.data.
tensor2matrix
(tensor, out=None)¶ Converts matrix to tensor
- Parameters
tensor ((..,6) array) – Input 3x3 array
out ((..,3,3) array, optional) – Output array.
- Returns
matrix – Matrix of shape (…,3,3).
- Return type
ndarray
-
dtmm.data.
matrix2tensor
(matrix, out=None)¶ Converts matrix to tensor
- Parameters
matrix ((..,6) array, optional) – Input 3x3 array
matrix – Output array.
- Returns
tensor – Tensor of shape (…,6).
- Return type
ndarray
-
dtmm.data.
split_block
(block_data)¶ Splits optical block data into a list of layers
-
dtmm.data.
layered_data
(optical_data)¶ Converts a list of blocks to a list of layers.
-
dtmm.data.
merge_blocks
(optical_data, shape=None, wavelength=None)¶ Merges blocks of optical data into a single block.
-
dtmm.data.
material_shape
(epsv, epsa)¶ Determines material 2D - crossection shape from the epsv -eigenvalues and epsa - eigenangles arrays
-
dtmm.data.
optical_block_shape
(optical_block)¶ Determines optical block 2D - crossection shape from the epsv -eigenvalues and epsa - eigenangles arrays
-
dtmm.data.
optical_data_shape
(optical_data)¶ Determines optical data 2D - crossection shape from the epsv -eigenvalues and epsa - eigenangles arrays
-
dtmm.data.
shape2dim
(shape)¶ Converts material 2D shape to material dimension
-
dtmm.data.
material_dim
(epsv, epsa)¶ Returns material dimension
-
dtmm.data.
save_stack
(file, optical_data)¶ Saves optical data to a binary file in
.dtms
format.- Parameters
file (file, str) – File or filename to which the data is saved. If file is a file-object, then the filename is unchanged. If file is a string, a
.dtms
extension will be appended to the file name if it does not already have one.optical_data (optical data tuple) – A valid optical data
-
dtmm.data.
load_stack
(file)¶ Load optical data from a file.
- Parameters
file (file, str) – The file to read.
dtmm.data_viewer
¶
Created on Mon Mar 19 10:32:48 2018
@author: andrej
Module Contents¶
-
dtmm.data_viewer.
plot_material
(data, eps=None, center=False, xlim=None, ylim=None, zlim=None, ax=None)¶ Plots material (in color) of the optical data.
- Parameters
data (optical_data or material (eps)) – A valid optical data tuple, eps array
eps (array or None, optional) – Specifies which eps values to plot. If not given, all data is plotted.
center (bool, optional) – Whether to view coordinates from the center of the box.
xlim ((low, high) or None, optional) – A tuple describing the coordinate limits in the x direction (width).
ylim ((low, high) or None, optional) – A tuple describing the coordinate limits in the y direction (height).
zlim ((low, high) or None, optional) – A tuple describing the coordinate limits in the z direction (layer index).
ax (matplotlib.axes or None, optional) – If specified, plot to ax.
-
dtmm.data_viewer.
plot_director
(director, fig=None, center=False, xlim=None, ylim=None, zlim=None, ax=None)¶ Plots director data.
- Parameters
director (optical_data or material (eps)) – A valid optical data tuple, eps array
eps (array or None, optional) – Specifies which eps values to plot. If not given, all data is plotted.
center (bool, optional) – Whether to view coordinates from the center of the box.
xlim ((low, high) or None, optional) – A tuple describing the coordinate limits in the x direction (width).
ylim ((low, high) or None, optional) – A tuple describing the coordinate limits in the y direction (height).
zlim ((low, high) or None, optional) – A tuple describing the coordinate limits in the z direction (layer index).
ax (matplotlib.axes or None, optional) – If specified, plot to ax.
-
dtmm.data_viewer.
plot_angles
(data, **kwargs)¶ Plots eps angles for optical data or angles data.
- Parameters
data (optical_data or material (eps)) – A valid optical data tuple, eps array
eps (array or None, optional) – Specifies which eps values to plot. If not given, all data is plotted.
center (bool, optional) – Whether to view coordinates from the center of the box.
xlim ((low, high) or None, optional) – A tuple describing the coordinate limits in the x direction (width).
ylim ((low, high) or None, optional) – A tuple describing the coordinate limits in the y direction (height).
zlim ((low, high) or None, optional) – A tuple describing the coordinate limits in the z direction (layer index).
ax (matplotlib.axes or None, optional) – If specified, plot to ax.
dtmm.denoise
¶
Field denoising functions.
Module Contents¶
-
dtmm.denoise.
denoise_field
(field, wavenumbers, beta, smooth=1, filter_func=exp_notch_filter, out=None)¶ Denoises field by attenuating modes around the selected beta parameter.
-
dtmm.denoise.
denoise_fftfield
(ffield, wavenumbers, beta, smooth=1, filter_func=exp_notch_filter, out=None)¶ Denoises fourier transformed field by attenuating modes around the selected beta parameter.
dtmm.diffract
¶
Diffraction calculation functions.
dtmm.fft
¶
Custom 2D FFT functions.
numpy, scipy and mkl_fft do not have fft implemented such that output argument can be provided. This implementation adds the output argument for fft2 and ifft2 functions.
Also, for mkl_fft and scipy, the computation can be performed in parallel using ThreadPool.
Module Contents¶
-
class
dtmm.fft.
PoolWorker
(queue)¶ Mimics the object returned by ThreadPool.apply_async method.
-
class
dtmm.fft.
Pool
(nthreads)¶ A multiprocessing.pool.ThreadPool -like object.
Implements only necessary part of ThreadPool API.
-
dtmm.fft.
clear_pool
()¶ Clears thread pool. Deletes all Pool objects, which terminates all running background threads.
-
dtmm.fft.
clear_cache
()¶ Clears fft cache data
-
dtmm.fft.
clear_planner
()¶ Clears fft planners (pyfftw)
-
dtmm.fft.
fft2
(a, out=None)¶ Computes fft2 of the input complex array.
- Parameters
a (array_like) – Input array (must be complex).
out (array or None, optional) – Output array. Can be same as input for fast inplace transform.
- Returns
out – Result of the transformation along the last two axes.
- Return type
complex ndarray
-
dtmm.fft.
ifft2
(a, out=None)¶ Computes ifft2 of the input complex array.
- Parameters
a (array_like) – Input array (must be complex).
out (array or None, optional) – Output array. Can be same as input for fast inplace transform.
- Returns
out – Result of the transformation along the last two axes.
- Return type
complex ndarray
-
dtmm.fft.
mfft2
(a, overwrite_x=False)¶ Computes matrix fft2 on a matrix of shape (…, n,n,4,4).
This is identical to np.fft2(a, axes = (-4,-3))
- Parameters
a (array_like) – Input array (must be complex).
overwrite_x (bool) – Specifies whether original array can be destroyed (for inplace transform)
- Returns
out – Result of the transformation along the (-4,-3) axes.
- Return type
complex ndarray
-
dtmm.fft.
mifft2
(a, overwrite_x=False)¶ Computes matrix ifft2 on a matrix of shape (…, n,n,4,4).
This is identical to np.ifft2(a, axes = (-4,-3))
- Parameters
a (array_like) – Input array (must be complex).
overwrite_x (bool) – Specifies whether original array can be destroyed (for inplace transform)
- Returns
out – Result of the transformation along the (-4,-3) axes.
- Return type
complex ndarray
-
dtmm.fft.
mfft
(a, overwrite_x=False)¶ Computes matrix fft on a matrix of shape (…, n,4,4).
This is identical to np.fft2(a, axis = -3)
- Parameters
a (array_like) – Input array (must be complex).
overwrite_x (bool) – Specifies whether original array can be destroyed (for inplace transform)
- Returns
out – Result of the transformation along the (-4,-3) axes.
- Return type
complex ndarray
-
dtmm.fft.
fft
(a, overwrite_x=False)¶ Computes fft on a matrix of shape (…, n).
This is identical to np.fft2(a)
- Parameters
a (array_like) – Input array (must be complex).
overwrite_x (bool) – Specifies whether original array can be destroyed (for inplace transform)
- Returns
out – Result of the transformation along the (-4,-3) axes.
- Return type
complex ndarray
-
dtmm.fft.
ifft
(a, overwrite_x=False)¶ Computes ifft on a matrix of shape (…, n).
This is identical to np.ifft2(a)
- Parameters
a (array_like) – Input array (must be complex).
overwrite_x (bool) – Specifies whether original array can be destroyed (for inplace transform)
- Returns
out – Result of the transformation along the (-4,-3) axes.
- Return type
complex ndarray
dtmm.field
¶
Field creation, transformation in IO functions
Module Contents¶
-
dtmm.field.
illumination_rays
(NA, diameter=5.0, smooth=0.1)¶ Returns beta, phi, intensity values for illumination.
This function can be used to define beta,phi,intensiy arrays that can be used to construct illumination data with the
illumination_data()
function. The resulting beta,phi parameters define directions of rays for the input light with a homogeneous angular distribution of rays - input light with a given numerical aperture.- Parameters
NA (float) – Approximate max numerical aperture of the illumination.
diameter (int or (int,int)) – Field aperture diaphragm diameter in pixels. Approximate number of rays is np.pi*(diameter/2)**2. If set as a tuple, it describes the inner and outer diameter.
smooth (float, optional) – Smoothness of diaphragm edge between 0. and 1.
- Returns
beta,phi, intensity – Ray parameters
- Return type
ndarrays
-
dtmm.field.
illumination_data
(shape, wavelengths, pixelsize=1.0, beta=0.0, phi=0.0, intensity=1.0, n=None, focus=0.0, window=None, backdir=False, jones=None, diffraction=True, eigenmodes=None, betamax=BETAMAX)¶ Constructs forward (or backward) propagating input illumination field data.
- Parameters
shape ((int,int)) – Shape of the illumination
wavelengths (array_like) – A list of wavelengths.
pixelsize (float, optional) – Size of the pixel in nm.
beta (float or array_like of floats, optional) – Beta parameter(s) of the illumination. (Default 0. - normal incidence)
phi (float or array_like of floats, optional) – Azimuthal angle(s) of the illumination.
n (float, optional) – Refractive index of the media that this illumination field is assumed to be propagating in (default to n_cover)
focus (float, optional) – Focal plane of the field. By default it is set at z=0.
window (array or None, optional) – If None, no window function is applied. This window function is multiplied with the constructed plane waves to define field diafragm of the input light. See
window.aperture()
.backdir (bool, optional) – Whether field is bacward propagating, instead of being forward propagating (default)
jones (jones vector or None, optional) – If specified it has to be a valid jones vector that defines polarization of the light. If not given (default), the resulting field will have two polarization components. See documentation for details and examples.
diffraction (bool, optional) – Specifies whether field is diffraction limited or not. By default, the field is filtered so that it has only propagating waves. You can disable this by specifying diffraction = False.
eigenmodes (bool or None) – If set to True (sefault value when window = None.), it defines whether to build eigenmodes from beta and phi values. In this case, beta and phi are only approximate values. If set to False (default when window != None), true beta and phi values are set.
betamax (float, optional) – The betamax parameter of the propagating field.
- Returns
illumination – A field data tuple.
- Return type
field_data
-
dtmm.field.
field2intensity
(field, out)¶ field2intensity(field)
Converts field array of shape […,4,height,width] to intensity array of shape […,height,width]. For each pixel element, a normal component of the Poynting vector is computed.
- Parameters
field (array_like) – Input field array
cmf (array_like) – Color matching function
- Returns
spec – Computed intensity array
- Return type
ndarray
-
dtmm.field.
field2specter
(field, out)¶ field2specter(field)
Converts field array of shape […,nwavelengths,4,height,width] to specter array of shape […,height,width,nwavelengths]. For each pixel element, a normal componentof Poynting vector is computed
- Parameters
field (array_like) – Input field array
cmf (array_like) – Color matching function
- Returns
spec – Computed specter array
- Return type
ndarray
-
dtmm.field.
validate_field_data
(data)¶ Validates field data.
This function inspects validity of the field data, and makes proper data conversions to match the field data format. In case data is not valid and it cannot be converted to a valid data it raises an exception (ValueError).
- Parameters
data (tuple of field data) – A valid field data tuple.
- Returns
data – Validated field data tuple.
- Return type
tuple
-
dtmm.field.
save_field
(file, field_data)¶ Saves field data to a binary file in
.dtmf
format.- Parameters
file (file, str, or pathlib.Path) – File or filename to which the data is saved. If file is a file-object, then the filename is unchanged. If file is a string, a
.dtmf
extension will be appended to the file name if it does not already have one.field_data ((field,wavelengths,pixelsize)) – A valid field data tuple
-
dtmm.field.
load_field
(file)¶ Load field data from file
- Parameters
file (file, str) – The file or filenam to read.
dtmm.field_viewer
¶
Matplotlib-based field visualizer (polarizing miscroscope simulator) and pom image calculation functions
pom_viewer()
for polarizing optical microscope simulation.field_viewer()
for raw field_data visualization.bulk_viewer()
for raw bulk_data visualization.calculate_pom_field()
calculates polarizing optical microscope field.
FieldViewer
is the actual field viewer object.BulkViewer
is the actual bulk viewer object.POMViewer
is the actual microscope viewer object.
Module Contents¶
-
dtmm.field_viewer.
calculate_pom_field
(field, jvec=None, pmat=None, dmat=None, window=None, input_fft=False, output_fft=False, out=None)¶ Calculates polarizing optical microscope field from the input field.
This function refocuses the field, applies polarizer and analayzers
- Parameters
field (ndarray) – Input array of shape (…,:,4,:,:) describing multiwavelength polarized field array or an array of shape (…,2,:,4,:,:) describing unpolarized (x nad y polarized) multiwavelength field arrays. Works also with jones multiwavelengths fields of shapes (…,:,2,:,:) and (…,2,:,2,:,:).
jvec (jonesvec, optional) – Normalized jones vector describing which polarization state of the input field to choose. Input field must be of unpolarized type if this parameter is specified.
pmat (ndarray, optional) – A 4x4 or 2x2 matrix describing the analyzer and retarder matrix. This matrix is applied in real space only if both input_fft and output_fft are False, otherwise, the matrix is applied in Fourier space.
dmat (ndarray, optional) – A diffraction matrix.
window (array, optional) – If specified, windowing is applied after field is diffracted.
input_fft (bool) – If specified, it idicates that we are working with fft data. pmat must be computed with mode_jonesmat4x4.
output_fft (bool) – If specified, output data is left in FFT space. No inverse Fourier transform is performed if this parameter is set to True.
out (ndarray, optional) – Output array.
- Returns
pom_field – Computed field.
- Return type
ndarray
Examples
>>> polarizer_jvec = dtmm.jones4.jonesvec((1,0)) >>> analyzer_jvec = dtmm.jones4.jonesvec((0,1)) >>> fmat = dtmm.tmm.f_iso() >>> pmat = dtmm.jones4.polarizer4x4(analyzer_jvec,fmat) >>> field_out = calculate_pom_field(nonpolarized_field_in, polarizer_jvec, pmat)
-
dtmm.field_viewer.
bulk_viewer
(field_data, **kwargs)¶ Returns a BulkViewer object for bulk field data visualization. See
field_viewer()
for parameters.- Returns
out – A
BulkViewer
viewer object- Return type
-
dtmm.field_viewer.
field_viewer
(field_data, cmf=None, bulk_data=False, n=1.0, mode=None, is_polarized=None, window=None, diffraction=True, polarization_mode='normal', betamax=BETAMAX, beta=None, **parameters)¶ Returns a FieldViewer object for field data visualization.
- Parameters
field_data (tuple[np.ndarray]) – Input field data
cmf (str, ndarray or None, optional) – Color matching function (table). If provided as an array, it must match input field wavelengths. If provided as a string, it must match one of available CMF names or be a valid path to tabulated data. See load_tcmf.
bulk_data (bool) – Specifies whether data is to be treated as bulk data, e.g as returned by the
transfer.transfer_field()
function with ret_bulk = True.n (float, optional) – Refractive index of the output material. Set this to the value used in the calculation of the field.
mode ([ 't' | 'r' | None], optional) – Viewer mode ‘t’ for transmission mode, ‘r’ for reflection mode None for as is data (no projection calculation - default).
is_polarized (bool, optional) – If specified, it defines whether the field is polarized or not. For non-polarized fields, the field must be of shape […,2,:,4,:,:]. If not provided, the polarization state is guessed from the shape of the input data. Setting this to False (and having non-polarized field) will allow setting the polarizer and sample rotation.
window (ndarray, optional) – Window function by which the calculated field is multiplied. This can be used for removing artefact from the boundaries.
diffraction (bool, optional) – Specifies whether field is treated as diffractive field or not (if it was calculated by diffraction > 0 algorithm or not). If set to False refocusing is disabled.
polarization_mode (str, optional) – Defines polarization mode. That is, how the polarization of the light is treated after passing the analyzer. By default, polarizer is applied in real space (normal) which is good for normal (or mostly normal) incidence light. You can use mode instead of normal for more accurate, but slower computation. Here polarizers are applied to mode coefficients in fft space.
betamax (float) – Betamax parameter used in the diffraction calculation function. With this you can simulate finite NA of the microscope (NA = betamax).
beta (ndarray, optional) – For multi-ray fields you must provide the beta array that was used to build the illumination data. Defining this parameter will allow you to re-adjust the aperture of the illumination by the ‘aperture’ parameter.
parameters (kwargs, optional) – Extra parameters passed directly to the
FieldViewer.set_parameters()
- Returns
out – A
FieldViewer
orBulkViewer
viewer object- Return type
-
class
dtmm.field_viewer.
FieldViewer
(shape, wavelengths, pixelsize, **kwargs)¶ Bases:
object
Field viewer. See
field_viewer()
-
property
ffield
(self)¶ Fourier transform of the field
-
property
focus
(self)¶ Focus position, relative to the calculated field position.
-
property
sample
(self)¶ Sample rotation angle
-
property
sample_angle
(self)¶ Sample rotation angle in degrees in float
-
property
aperture
(self)¶ Illumination field aperture
-
property
aperture_mask
(self)¶ Illuminetion field aperture mask array
-
property
masked_field
(self)¶ Field masked with aperture_mask.
-
property
masked_ffield
(self)¶ Fourier transform of the field masked with aperture_mask.
-
property
polarizer
(self)¶ Polarizer angle. Can be ‘h’,’v’, ‘lcp’, ‘rcp’, ‘none’, angle float or a jones vector
-
property
analyzer
(self)¶ Analyzer angle. Can be ‘h’,’v’, ‘lcp’, ‘rcp’, ‘none’, angle float or a jones vector
-
property
retarder
(self)¶ Name of the retarder placed in front of the analyzer. Can be any of ‘lambda’, ‘lambda/4’ or ‘lambda/2’. The ‘lambda/4’ or ‘lambda/2 are simulated as a pozitive birefringent ideal (non-dispersive) quarte and half wave plate with the slow axis at +45 degrees with respect to the horizontal axis. The ‘lambda’ plate is a full plate for 530 nm with the slow axis at +45 degrees
-
property
intensity
(self)¶ Input light intensity
-
property
input_jones
(self)¶ Input field jones vector
-
property
diffraction_matrix
(self)¶ Diffraction matrix for diffraction calculation
-
property
output_matrix
(self)¶ 4x4 jones output matrix
-
set_parameters
(self, **kwargs)¶ Sets viewer parameters. Any of the
VIEWER_PARAMETERS
-
get_parameters
(self)¶ Returns viewer parameters as dict
-
plot
(self, fig=None, ax=None, sliders=None, show_sliders=None, show_scalebar=None, show_ticks=None, **kwargs)¶ Plots field intensity profile. You can set any of the below listed arguments. Additionaly, you can set any argument that imshow of matplotlib uses (e.g. ‘interpolation = “sinc”’).
- Parameters
show_sliders (bool, optional) – Specifies whether to show sliders or not.
show_scalebar (bool, optional) – Specifies whether to show scalebar or not.
show_ticks (bool, optional) – Specifies whether to show ticks in imshow or not.
fmin (float, optional) – Minimimum value for the focus setting.
fmax (float, optional) – Maximum value for the focus setting.
imin (float, optional) – Minimimum value for then intensity setting.
imax (float, optional) – Maximum value for then intensity setting.
pmin (float, optional) – Minimimum value for the polarizer angle.
pmax (float, optional) – Maximum value for the polarizer angle.
smin (float, optional) – Minimimum value for the sample rotation angle.
smax (float, optional) – Maximum value for the sample rotation angle.
amin (float, optional) – Minimimum value for the analyzer angle.
amax (float, optional) – Maximum value for the analyzer angle.
namin (float, optional) – Minimimum value for the numerical aperture.
namax (float, optional) – Maximum value for the numerical aperture.
-
calculate_specter
(self, **params)¶ Calculates field specter.
- Parameters
params (kwargs, optional) – Any additional keyword arguments that are passed dirrectly to set_parameters method.
-
calculate_image
(self, **params)¶ Calculates RGB image.
- Parameters
params (keyword arguments) – Any additional keyword arguments that are passed dirrectly to set_parameters method.
-
save_image
(self, fname, origin='lower', **kwargs)¶ Calculates and saves image to file using matplotlib.image.imsave.
- Parameters
fname (str) – Output filename or file object.
origin ([ 'upper' | 'lower' ]) – Indicates whether the (0, 0) index of the array is in the upper left or lower left corner of the axes. Defaults to ‘lower’
kwargs (optional) – Any extra keyword argument that is supported by matplotlib.image.imsave
-
update_plot
(self)¶ Triggers plot redraw
-
show
(self)¶ Shows plot
-
property
-
class
dtmm.field_viewer.
BulkViewer
(shape, wavelengths, pixelsize, **kwargs)¶ Bases:
FieldViewer
Field viewer. See
field_viewer()
-
property
focus
(self)¶ Focus position
-
property
masked_field
(self)¶ Field masked with aperture_mask.
-
property
masked_ffield
(self)¶ Fourier transform of the field masked with aperture_mask.
-
property
diffraction_matrix
(self)¶ Diffraction matrix for diffraction calculation
-
property
dtmm.hashing
¶
Taken from dask.hasking
Module Contents¶
-
dtmm.hashing.
hash_buffer
(buf, hasher=None)¶ Hash a bytes-like (buffer-compatible) object. This function returns a good quality hash but is not cryptographically secure. The fastest available algorithm is selected. A fixed-length bytes object is returned.
-
dtmm.hashing.
hash_buffer_hex
(buf, hasher=None)¶ Same as hash_buffer, but returns its result in hex-encoded form.
dtmm.jones
¶
Jones calculus functions. You can use this module for simple normal incidence jones calculus.
2x2 matrices¶
jonesvec()
: jones vectormirror()
: mirror matrixpolarizer()
: polarizer matrixretarder()
: retarder matrixquarter_waveplate()
: quarter-wave plate matrixhalf_waveplate()
: half-wave plate matrixcircular_polarizer()
: circular polarizer matrixlinear_polarizer()
: linear polarizer matrix
Conversion functions¶
as4x4()
: convert to 4x4 matrix for (…,4) field vector.rotated_matrix()
: to view the matrix in rotated frame.
Examples
>>> j_in = jonesvec((1,1)) #input light polarized at 45
>>> r = retarder(0.2,0.4)
>>> p = linear_polarizer((1,0)) # x polarization
>>> c = circular_polarizer(+1) # left handed
>>> m = multi_dot([r,p,c])
>>> j_out = dotmv(m,j_in) #output light E field
>>> i = jones_intensity(j_out) #intensity
Module Contents¶
-
dtmm.jones.
jones_intensity
(jones)¶ Computes intensity of the jones vector
- Parameters
jones ((..,2) array) – Jones vector.
- Returns
intensity – Computed intensity.
- Return type
(..) float array
-
dtmm.jones.
jonesvec
(pol, phi=0.0, out=None)¶ Returns a normalized jones vector from an input length 2 vector., Additionaly, you can use this function to view the jones vector in rotated coordinate frame, defined with a rotation angle phi.
Numpy broadcasting rules apply.
- Parameters
pol ((..,2) array) – Input jones vector. Does not need to be normalized.
phi (float or (..,1) array) – If jones vector must be view in the rotated frame, this parameter defines the rotation angle.
out (ndarray) – Output array in which to put the result; if provided, it must have a shape that the inputs broadcast to.
- Returns
vec – Normalized jones vector
- Return type
ndarray
Example
>>> jonesvec((1,1j)) #left-handed circuar polarization array([0.70710678+0.j , 0. +0.70710678j])
In rotated frame
>>> j1,j2 = jonesvec((1,1j), (np.pi/2,np.pi/4)) >>> np.allclose(j1, (0.70710678j,-0.70710678)) True >>> np.allclose(j2, (0.5+0.5j,-0.5+0.5j)) True
-
dtmm.jones.
mirror
(out=None)¶ Returns jones mirror matrix.
- Parameters
out (ndarray, optional) – Output array in which to put the result; if provided, it must have a shape that the inputs broadcast to.
- Returns
mat – Output jones matrix.
- Return type
ndarray
-
dtmm.jones.
retarder
(phase, phi=0.0, out=None)¶ Returns jones matrix of general phase retarder
Numpy broadcasting rules apply.
- Parameters
phase (float or array) – Phase difference between the slow and fast axis of the retarder.
phi (float or array) – Slow axis orientation
out (ndarray, optional) – Output array in which to put the result; if provided, it must have a shape that the inputs broadcast to.
- Returns
mat – Output jones matrix.
- Return type
ndarray
-
dtmm.jones.
quarter_waveplate
(phi=0.0, out=None)¶ Returns jones quarter-wave plate matrix.
Numpy broadcasting rules apply.
- Parameters
phi (float or array) – Slow axis orientation
out (ndarray, optional) – Output array in which to put the result; if provided, it must have a shape that the inputs broadcast to.
- Returns
mat – Output jones matrix.
- Return type
ndarray
-
dtmm.jones.
half_waveplate
(phi=0.0, out=None)¶ Returns jones half-wave plate matrix.
Numpy broadcasting rules apply.
- Parameters
phi (float or array) – Slow axis orientation
out (ndarray, optional) – Output array in which to put the result; if provided, it must have a shape that the inputs broadcast to.
- Returns
mat – Output jones matrix.
- Return type
ndarray
-
dtmm.jones.
full_waveplate
(phi=0.0, central=530.0, wavelengths=None, out=None)¶ Returns jones full-wave plate matrix.
Numpy broadcasting rules apply.
- Parameters
phi (float or array) – Slow axis orientation
central (float) – Central wavelength for which to define the lambda plate. Used only if wavelengths are set.
wavelengths (array, optional) – An array of wavelength around the central wavelength for which we compute the retarder jones matrix.
out (ndarray, optional) – Output array in which to put the result; if provided, it must have a shape that the inputs broadcast to.
- Returns
mat – Output jones matrix.
- Return type
ndarray
-
dtmm.jones.
polarizer
(jones, out=None)¶ Returns jones polarizer matrix.
Numpy broadcasting rules apply.
- Parameters
jones ((..,2) array) – Input normalized jones vector. Use
jonesvec()
to generate jones vectorout (ndarray, optional) – Output array in which to put the result; if provided, it must have a shape that the inputs broadcast to.
- Returns
mat – Output jones matrix.
- Return type
ndarray
Examples
>>> pmat = polarizer(jonesvec((1,1))) #45 degree linear polarizer >>> np.allclose(pmat, linear_polarizer(np.pi/4)+0j ) True >>> pmat = polarizer(jonesvec((1,-1))) #-45 degree linear polarizer >>> np.allclose(pmat, linear_polarizer(-np.pi/4)+0j ) True >>> pmat = polarizer(jonesvec((1,1j))) #left handed circular polarizer >>> np.allclose(pmat, circular_polarizer(1) ) True
-
dtmm.jones.
linear_polarizer
(angle, out=None)¶ Return jones matrix for a polarizer.
Numpy broadcasting rules apply.
- Parameters
angle (float or array) – Orientation of the polarizer.
out (ndarray, optional) – Output array in which to put the result; if provided, it must have a shape that the inputs broadcast to.
- Returns
mat – Output jones matrix.
- Return type
ndarray
-
dtmm.jones.
circular_polarizer
(hand, out=None)¶ Returns circular polarizer matrix.
Numpy broadcasting rules apply.
- Parameters
hand (int or (..,1) array) – Handedness +1 (left-hand) or -1 (right-hand).
out (ndarray, optional) – Output array in which to put the result; if provided, it must have a shape that the inputs broadcast to.
- Returns
mat – Output jones matrix.
- Return type
ndarray
-
dtmm.jones.
rotated_matrix
(jmat, phi)¶ jones matrix viewed in the rotated frame, where phi is the rotation angle
Performs (R.T).jmat.R where R is the rotation matrix.
Numpy broadcasting rules apply.
- Parameters
jmat ((..,2,2) array) – Jones matrix
phi (float) – Rotation angle.
- Returns
out – Rotated jones matrix.
- Return type
(..,2,2) array
-
dtmm.jones.
as4x4
(jmat, out=None)¶ Converts jones 2x2 matrix to eigenfield 4x4 matrix.
- Parameters
jmat ((..,2,2) array) – Jones matrix
out (ndarray, optional) – Output array in which to put the result; if provided, it must have a shape that the inputs broadcast to.
- Returns
mat – Output jones matrix.
- Return type
(..,4,4) ndarray
dtmm.jones4
¶
Field vector and field data polarization and phase retardation matrix functions and handling.
Polarization and retardation handling¶
polarizer4x4()
creates a polarizer matrix.jonesmat4x4()
creates a general jones 4x4 matrix from 2x2 jones patrix.mode_jonesmat4x4()
creates a general jones 4x4 matrix for field data in fft space.ray_jonesmat4x4()
creates a general jones 4x4 matrix for field data in real space.
Convenience functions¶
apply_mode_jonesmat4x4()
to apply the matrix to field data in fft spaceapply_ray_jonesmat4x4()
to apply the matrix to field data in real spaceapply_jonesmat()
to apply the matrix to field vector (1D).
Module Contents¶
-
dtmm.jones4.
as2x2
(pmat, fmat, mode=+ 1, out=None)¶ Converts jones 4x4 matrix to 2x2 E-field matrix
-
dtmm.jones4.
polarizer4x4
(jones, fmat, out=None)¶ Returns a 4x4 polarizer matrix for applying in eigenframe.
Numpy broadcasting rules apply.
- Parameters
jones ((..,2) array) – A length two array describing the jones vector in the eigenframe. Jones vector should be normalized.
fmat ((..,4,4) array) – A field matrix array of the isotropic medium.
out (ndarray, optional) – Output array.
- Returns
jmat – A 4x4 matrix for field vector manipulation in the eigenframe.
- Return type
(..,4,4) array
See also
ray_jonesmat4x4
for applying a general matrix in the laboratory frame.
Examples
>>> f = dtmm.tmm.f_iso(n = 1.) >>> jones = dtmm.jones.jonesvec((1,0)) >>> pol_mat = polarizer4x4(jones, f) #x polarizer matrix
-
dtmm.jones4.
jonesmat4x4
(jmat, fmat, out=None)¶ Returns a 4x4 jones matrix for applying in eigenframe.
Numpy broadcasting rules apply.
- Parameters
jmat ((..,2,2) array) – A 2x2 jones matrix in the eigenframe. Any of matrices in
dtmm.jones
can be used.fmat ((..,4,4) array) – A field matrix array of the isotropic medium.
out (ndarray, optional) – Output array
- Returns
jmat – A 4x4 matrix for field vector manipulation in the eigenframe.
- Return type
(..,4,4) array
See also
ray_jonesmat4x4
for applying the jones matrix in the laboratory frame.
-
dtmm.jones4.
mode_jonesmat4x4
(shape, k, jmat, epsv=(1.0, 1.0, 1.0), epsa=(0.0, 0.0, 0.0), betamax=BETAMAX)¶ Returns a mode polarizer for fft of the field data in the laboratory frame.
This is the most general set of jones matrices for field data. It is meant to be used in FFT space.
- Parameters
shape ((int,int)) – Shape of the 2D crossection of the field data.
k (float or array of floats) – Wavenumber at which to compute the mode matrices.
jmat ((2,2) array) – A 2x2 jones matrix that needs to be converted to 4x4 mode matrices.
epsv (array) – Medium epsilon eigenvalues
epsa (array) – Medium epsilon euler angles
betamax (float) – The betamax parameter
- Returns
pmat – Output matrix. Shape of the matirx is shape + (4,4) or len(ks) + shape + (4,4) if k is an array.
- Return type
(:,:,4,4) array
See also
ray_jonesmat4x4
for applying the jones matrix in the real space.
jonesmat4x4
for applying the jones matrix in the eigenframe.
-
dtmm.jones4.
mode_jonesmat2x2
(shape, k, jmat, epsv=(1.0, 1.0, 1.0), epsa=(0.0, 0.0, 0.0), mode=+ 1, betamax=BETAMAX)¶ Returns a mode polarizer for fft of the field data in the laboratory frame.
This is the most general set of jones matrices for E-field data. It is meant to be used in FFT space.
- Parameters
shape ((int,int)) – Shape of the 2D crossection of the field data.
k (float or array of floats) – Wavenumber at which to compute the mode matrices.
jmat ((2,2) array) – A 2x2 jones matrix that needs to be converted to 4x4 mode matrices.
epsv (array) – Medium epsilon eigenvalues
epsa (array) – Medium epsilon euler angles
mode (int) – PRopagatin mode, either +1 or -1
betamax (float) – The betamax parameter
- Returns
pmat – Output matrix. Shape of the matirx is shape + (2,2) or len(ks) + shape + (2,2) if k is an array.
- Return type
(:,:,2,2) array
See also
ray_jonesmat2x2
for applying the jones matrix in the real space.
-
dtmm.jones4.
ray_jonesmat4x4
(jmat, beta=0, phi=0, epsv=(1.0, 1.0, 1.0), epsa=(0.0, 0.0, 0.0))¶ Returns a ray polarizer for field data in the laboratory frame.
Numpy broadcasting rules apply.
- Parameters
jmat ((..,2,2) array) – A 2x2 jones matrix that needs to be converted to 4x4 mode matrices.
beta (float) – The beta parameter of the beam.
phi (float) – The phi parameter of the beam.
epsv ((..,3) array) – Medium epsilon eigenvalues
epsa ((..,3) array) – Medium epsilon euler angles
betamax (float) – The betamax parameter
- Returns
pmat – Output matrix.
- Return type
(..,4,4) array
See also
mode_jonesmat4x4
for applying the jones matrix in the fft space.
jonesmat4x4
for applying the jones matrix in the eigenframe.
-
dtmm.jones4.
ray_jonesmat2x2
(jmat, beta=0, phi=0, epsv=(1.0, 1.0, 1.0), epsa=(0.0, 0.0, 0.0), mode=+ 1)¶ Returns a ray polarizer for E-field data in the laboratory frame.
Numpy broadcasting rules apply.
- Parameters
jmat ((..,2,2) array) – A 2x2 jones matrix that needs to be converted to 2x2 mode matrices.
beta (float) – The beta parameter of the beam.
phi (float) – The phi parameter of the beam.
epsv ((..,3) array) – Medium epsilon eigenvalues
epsa ((..,3) array) – Medium epsilon euler angles
betamax (float) – The betamax parameter
- Returns
pmat – Output matrix.
- Return type
(..,2,2) array
See also
mode_jonesmat2x2
for applying the jones matrix in the fft space.
jonesmat2x2
for applying the jones matrix in the eigenframe.
-
dtmm.jones4.
apply_mode_jonesmat
(pmat, field, out=None)¶ Multiplies matrix with field data in fft space.
- Parameters
pmat (array) – A 4x4 jones matrix of shape (…,:,:,4,4) for field data or 2x2 jones matrix of shape (…,:,:,2,2) for E-field data or
field (array) – Field data array of shape (…,4,:,:) or (…,2,:,:).
out (ndarray, optional) – If specified, the results are written here.
- Returns
out – Computed field array of shape (…,4,:,:) or (…,2,:,:).
- Return type
array
-
dtmm.jones4.
apply_ray_jonesmat
(pmat, field, out=None)¶ Multiplies matrix with field data in real space.
- Parameters
pmat (array) – A 4x4 jones matrix of shape (…,4,4) for field data or 2x2 jones matrix of shape (…,2,2) for E-field data or
field (array) – Field data array of shape (…,4,:,:) or (…,2,:,:).
out (array, optional) – If specified, the results are written here.
- Returns
out – Computed field array of shape (…,4,:,:) or (…,2,:,:).
- Return type
ndarray
-
dtmm.jones4.
apply_jonesmat
(pmat, field, out=None)¶ Multiplies a (2x2) or (4x4) jones matrix with field vector
- Parameters
pmat (ndarray) – A 4x4 jones matrix of shape (…,4,4) for field data or 2x2 jones matrix of shape (…,2,2) for E-field data or
field (array) – Field vector array of shape (…,4) or (…,2).
out (array, optional) – If specified, the results are written here.
- Returns
out – Computed field array of shape (…,4).
- Return type
ndarray
dtmm.linalg
¶
Numba optimized linear algebra functions for 4x4 matrices and 2x2 matrices.
Module Contents¶
-
dtmm.linalg.
eig
(matrix, overwrite_x=False)¶ Computes eigenvalues and eigenvectors of 3x3 matrix using numpy.linalg.eig. Eigenvalues are sorted so that eig[2] is the most distinct (extraordinary).
- Parameters
matrix ((..,3,3) array) – A 3x3 matrix.
overwrite_x (bool, optional) – Ifset, the function will write eigenvectors as rows in the input array.
- Returns
w ((…, 3) array) – The eigenvalues, each repeated according to its multiplicity. The eigenvalues are ordered so that the third eigenvalue is most distinct and first two are least distinct
v ((…, 3, 3) array) – The normalized (unit “length”) eigenvectors, such that the column
v[:,i]
is the eigenvector corresponding to the eigenvaluew[i]
.
-
dtmm.linalg.
tensor_eig
(tensor, overwrite_x=False)¶ Computes eigenvalues and eigenvectors of a tensor.
Eigenvalues are sorted so that eig[2] is the most distinct (extraordinary).
If tensor is provided as a length 6 matrix, the elements are a[0,0], a[1,1], a[2,2], a[0,1], a[0,2], a[1,2]. If provided as a (3x3) matrix a, the rest of the elements are silently ignored.
- Parameters
tensor ((..,6) or (..,3,3) array) – A length 6 array or 3x3 matrix
overwrite_x (bool, optional) – If tensor is (…,3,3) array, the function will write eigenvectors as rows in the input array.
- Returns
w ((…, 3) array) – The eigenvalues, each repeated according to its multiplicity. The eigenvalues are ordered so that the third eigenvalue is most distinct and first two are least distinct
v ((…, 3, 3) array) – The normalized (unit “length”) eigenvectors, such that the column
v[:,i]
is the eigenvector corresponding to the eigenvaluew[i]
.
-
dtmm.linalg.
inv
(mat, out)¶ inv(mat), gufunc
Calculates inverse of a 4x4 complex matrix or 2x2 complex matrix
- Parameters
mat (ndarray) – Input array
Examples
>>> a = np.random.randn(4,4) + 0j >>> ai = inv(a)
>>> from numpy.linalg import inv >>> ai2 = inv(a)
>>> np.allclose(ai2,ai) True
-
dtmm.linalg.
dotmf
(a, b, out=None)¶ dotmf(a, b)
Computes a dot product of an array of 4x4 (or 2x2) matrix with a field array or an E-array (in case of 2x2 matrices).
-
dtmm.linalg.
dotmm
(a, b, out)¶ dotmm(a, b)
Computes an efficient dot product of a 4x4, 2x2 or a less efficient general matrix multiplication.
-
dtmm.linalg.
dotmd
(a, d, out)¶ dotmd(a, d)
Computes a dot product of a 4x4 (or 2x2) matrix with a diagonal matrix represented by a vector of shape 4 (or 2).
-
dtmm.linalg.
dotmv
(a, b, out)¶ dotmv(a, b)
Computes a dot product of a 4x4 or 2x2 matrix with a vector.
-
dtmm.linalg.
dotmdm
(a, d, b, out)¶ dotmdm(a, d, b)
Computes a dot product of a 4x4 (or 2x2) matrix with a diagonal matrix (4- or 2-vector) and another 4x4 (or 2x2) matrix.
-
dtmm.linalg.
multi_dot
(arrays, axis=0, reverse=False)¶ Computes dot product of multiple 2x2 or 4x4 matrices. If reverse is specified, it is performed in reversed order. Axis defines the axis over which matrices are multiplied.
dtmm.matrix
¶
Diffraction matrices used in the difraction step of the layer propagation functions
dtmm.print_tools
¶
Message printing functions. cddm uses cddm.conf.CDDMConfig.verbose variable to define verbosity level and behavior of printing functions.
verbosity levels 1 and 2 enable printing, 0 disables printing messages.
Module Contents¶
-
dtmm.print_tools.
print1
(*args, **kwargs)¶ prints level 1 messages
-
dtmm.print_tools.
print2
(*args, **kwargs)¶ prints level 2 messages
-
dtmm.print_tools.
print_progress
(iteration, total, prefix='', suffix='', decimals=1, length=50, fill='=', level=None)¶ Call in a loop to create terminal progress bar
-
dtmm.print_tools.
print_frame_rate
(n_frames, t0, t1=None, message='... processed')¶ Prints calculated frame rate
-
dtmm.print_tools.
disable_prints
()¶ Disable message printing. Returns previous verbosity level
-
dtmm.print_tools.
enable_prints
(level=None)¶ Enable message printing. Returns previous verbosity level
dtmm.propagate_2x2
¶
The 2x2 layer propagation functions
dtmm.propagate_4x4
¶
The 4x4 layer propagation functions
dtmm.rotation
¶
Rotation matrices and conversion functions.
Rotation matrices¶
rotation_vector2()
: 2D rotation vector.
rotation_matrix2()
: 2D rotation matrix.
rotation_matrix_z()
: 3D rotation matrix around z.
rotation_matrix_x()
: 3D rotation matrix around x.
rotation_matrix_y()
: 3D rotation matrix around y.
rotation_matrix()
: general 3D rotation matrix from Euler angles.
Conversion functions¶
rotate_diagonal_tensor()
for 3D diagonal tensor rotation.
rotate_tensor()
for 3D tensor rotation.
rotate_vector()
for 3D vector rotation.
rotation_angles()
Converts rotation matrix to Euler angles
Module Contents¶
-
dtmm.rotation.
rotation_vector2
(angle, out=None)¶ Converts the provided angle into a rotation vector (cos, sin).
- Parameters
angle (array) – Array containing the angle of rotation at different points in space
out (array) – Rotation, represented as a 2D vector at every point in space
-
dtmm.rotation.
rotation_matrix2
(angle, out=None)¶ Returns 2D rotation matrix.
Numpy broadcasting rules apply.
-
dtmm.rotation.
rotation_matrix_z
(angle, out=None)¶ Calculates a rotation matrix for rotations around the z axis.
Numpy broadcasting rules apply.
-
dtmm.rotation.
rotation_matrix_y
(angle, out=None)¶ Calculates a rotation matrix for rotations around the y axis.
Numpy broadcasting rules apply.
-
dtmm.rotation.
rotation_matrix_x
(angle, out=None)¶ Calculates a rotation matrix for rotations around the x axis.
Numpy broadcasting rules apply.
-
dtmm.rotation.
rotation_matrix
(angles, out)¶ rotation_matrix(angles, out)
Calculates a general rotation matrix for rotations z-y-z psi, theta, phi. If out is specified.. it should be 3x3 float matrix.
- Parameters
angles (array_like) – A length 3 vector of the three angles
Examples
>>> a = rotation_matrix([0.12,0.245,0.78])
The same can be obtained by:
>>> Ry = rotation_matrix_z(0.12) >>> Rt = rotation_matrix_y(0.245) >>> Rf = rotation_matrix_z(0.78)
>>> b = np.dot(Rf,np.dot(Rt,Ry)) >>> np.allclose(a,b) True
-
dtmm.rotation.
rotation_angles
(matrix, out)¶ Computes Euler rotation angles from rotation matrix.
Numpy broadcasting rules apply.
- Parameters
matrix ((.., 3,3) array) – Rotation matrix
out (ndarray, optional) – Output array
- Returns
angles – Euler angles : psi (z rotation), theta (x rotation), phi (z rotation).
- Return type
(..,3) ndarray
-
dtmm.rotation.
rotate_diagonal_tensor
(R, diagonal, out=None)¶ Rotates a diagonal tensor, based on the rotation matrix provided
>>> R = rotation_matrix((0.12,0.245,0.78)) >>> diag = np.array([1.3,1.4,1.5], dtype = CDTYPE) >>> tensor = rotate_diagonal_tensor(R, diag) >>> matrix = dtmm.data.tensor2matrix(tensor)
The same can be obtained by:
>>> Ry = rotation_matrix_z(0.12) >>> Rt = rotation_matrix_y(0.245) >>> Rf = rotation_matrix_z(0.78) >>> R = np.dot(Rf,np.dot(Rt,Ry))
>>> diag = np.diag([1.3,1.4,1.5]) + 0j >>> matrix2 = np.dot(R,np.dot(diag, R.transpose()))
>>> np.allclose(matrix2,matrix) True
-
dtmm.rotation.
rotate_tensor
(R, tensor, out)¶ Calculates out = R.tensor.RT of a tensor”
>>> R = rotation_matrix((0.12,0.245,0.78)) >>> tensor = np.array([1.3,1.4,1.5,0.1,0.2,0.3], dtype = CDTYPE) >>> tensor = rotate_tensor(R, tensor) >>> matrix = tensor2matrix(tensor)
-
dtmm.rotation.
rotate_vector
(rotation_matrix, vector, out)¶ Rotates vector <vector> using rotation matrix <rotation_matrix> rotate_vector(R, vector)
Calculates out = R.vector of a vector.
- Parameters
rotation_matrix (array) – 3x3 rotation matrix
vector (array) – Input 3-vector to rotate
out (array, optional) – Output rotated 3-vector
- Returns
vector – Rotated vector.
- Return type
ndarray
dtmm.solver
¶
TMM Matrix solvers for 3d, 2d and 1d data.
These objects can be used for a simplified treatment of the transfer matrices for 3d field data on 1d, 2d (and 3d) optical data.
MatrixBlockSolver3D
for matrix-based 3d simulations on optical blocks.MatrixDataSolver3D
for matrix-based 3d simulations on optical datas.
Module Contents¶
-
class
dtmm.solver.
BaseMatrixSolver2D
(shape, betay=0, wavelengths=[500], pixelsize=100, mask=None, method='4x4', betamax=None)¶ Bases:
object
Base class for all 2D Matrix-based solvers.
-
set_mask
(self, mask)¶ Sets fft mask.
- Parameters
mask (ndarray) – A boolean mask, describing fft modes that are used in the solver.
-
property
field_in
(self)¶ Input field array
-
get_field_data_in
(self, copy=True)¶ Returns input field data tuple.
If copy is set to True (default), a copy of the field_out array is made.
-
property
field_out
(self)¶ Output field array
-
get_field_data_out
(self, copy=True)¶ Returns output field data tuple.
If copy is set to True (default), a copy of the field_out array is made.
-
calculate_field_matrix
(self, nin=1.0, nout=1.0)¶ Calculates field matrices.
This must be called after you set material data.
-
calculate_reflectance_matrix
(self)¶ Calculates reflectance matrix.
Available in “4x4”,”4x4_1” methods only. This must be called after you have calculated the stack and field matrices.
-
calculate_transmittance_matrix
(self)¶ Calculates transmittance matrix.
Available in “2x2” method only. This must be called after you have calculated the stack matrix.
-
transfer_field
(self, field_in=None, field_out=None)¶ Transfers field.
This must be called after you have calculated the transmittance/reflectance matrix.
- Parameters
field_in (ndarray, optional) – If set, the field_in attribute will be set to this value prior to transfering the field.
field_out (ndarray, optional) – If set, the field_out attribute will be set to this value prior to transfering the field.
-
-
class
dtmm.solver.
BaseMatrixSolver3D
(shape, wavelengths=[500], pixelsize=100, mask=None, method='4x4', betamax=None)¶ Bases:
object
Base class for all Matrix-based solvers.
-
set_mask
(self, mask)¶ Sets fft mask.
- Parameters
mask (ndarray) – A boolean mask, describing fft modes that are used in the solver.
-
property
field_in
(self)¶ Input field array
-
get_field_data_in
(self, copy=True)¶ Returns input field data tuple.
If copy is set to True (default), a copy of the field_out array is made.
-
property
field_out
(self)¶ Output field array
-
get_field_data_out
(self, copy=True)¶ Returns output field data tuple.
If copy is set to True (default), a copy of the field_out array is made.
-
calculate_field_matrix
(self, nin=1.0, nout=1.0)¶ Calculates field matrices.
This must be called after you set material data.
-
calculate_reflectance_matrix
(self)¶ Calculates reflectance matrix.
Available in “4x4”,”4x4_1” methods only. This must be called after you have calculated the stack and field matrices.
-
calculate_transmittance_matrix
(self)¶ Calculates transmittance matrix.
Available in “2x2” method only. This must be called after you have calculated the stack matrix.
-
transfer_field
(self, field_in=None, field_out=None)¶ Transfers field.
This must be called after you have calculated the transmittance/reflectance matrix.
- Parameters
field_in (ndarray, optional) – If set, the field_in attribute will be set to this value prior to transfering the field.
field_out (ndarray, optional) – If set, the field_out attribute will be set to this value prior to transfering the field.
-
-
class
dtmm.solver.
MatrixBlockSolver3D
(shape, wavelengths=[500], pixelsize=100, mask=None, method='4x4', betamax=None)¶ Bases:
BaseMatrixSolver3D
TMM matrix solver for 1d,2d or 3d optical block data using 3d field data.
Examples
# initialize with a problem shape, wavelengths and pixelsize >>> solver = MatrixBlockSolver3D(shape = (96,96), wavelengths = [500,550], pixelsize = 100)
# set optical data first. Data must be compatible with the solver shape. >>> solver.set_optical_block(optical_block)
# main transfer matrix calculation procedure. >>> solver.calculate_stack_matrix()
# set input and putput field matrices. These can be set without re-computing # the stack matrix. >>> solver.calculate_field_matrix(nin = 1.5, nout = 1.5)
# each time you change input/ouptut field matrices you must recompute # the reflectance matrix. >>> solver.calculate_reflectance_matrix()
# now transfer some input, optionally set also output field… >>> solver.transfer_field(field_in = field_in) # you can do this many times with different input fields.. >>> solver.transfer_field(field_in = field_in)
# obtain results >>> field_data_out = solver.get_field_data_out() >>> field_data_in = solver.get_field_data_in()
-
set_optical_block
(self, data)¶ Sets optical block data.
-
calculate_layer_matrices
(self)¶ Calculates layer matrices. Results are storred in the layers_matrices attribute.
-
calculate_stack_matrix
(self, keep_layer_matrices=False)¶ Calculates the block stack matrix. Results are storred in the stack_matrix attribute.
- Parameters
keep_layer_matrices (bool) – If set to True, it will store layer_matrices in the layer_matrices attribute.
-
propagate_field
(self, field=None)¶ Propagates field over the stack. Returns an iterator. Each next value of the iterator is a result of field propagation over each next layer in the optical block.
For “4x4” methods, it propagates from the ouptut layer to the input layer. For “2x2” method, it propagates from the input layer to the output layer.
- Parameters
field (ndarray, optional) – Field array that is propagated. If not set, field_out attribute is used for “4x4” methods and field_in attribute is used for the “2x2” method.
- Yields
field (ndarray) – Field array.
-
calculate_bulk_field
(self, field=None, out=None)¶ Propagates field and calculates bulk field data.
- Parameters
field (ndarray, optional) – Field array that is propagated. If not set, field_out attribute is used for “4x4” methods and field_in attribute is used for the “2x2” method.
out (ndarray, optional) – Output array for storring the bulk data.
-
-
class
dtmm.solver.
MatrixDataSolver3D
(shape, wavelengths=[500], pixelsize=100, mask=None, method='4x4', betamax=None)¶ Bases:
BaseMatrixSolver3D
TMM matrix solver for 1d,2d or 3d optical data using 3d field data.
Examples
# initialize with a problem shape, wavelengths and pixelsize >>> solver = MatrixBlockSolver3D(shape = (96,96), wavelengths = [500,550], pixelsize = 100)
# set optical data first. Data must be compatible with the solver shape. >>> solver.set_optical_data(optical_data)
# main transfer matrix calculation procedure. >>> solver.calculate_stack_matrix()
# set input and putput field matrices. These can be set without re-computing # the stack matrix. >>> solver.calculate_field_matrix(nin = 1.5, nout = 1.5)
# each time you change input/ouptut field matrices you must recompute # the reflectance matrix. >>> solver.calculate_reflectance_matrix()
# now transfer some input, optionally set also output field… >>> solver.transfer_field(field_in = field_in) # you can do this many times with different input fields.. >>> solver.transfer_field(field_in = field_in)
# obtain results >>> field_data_out = solver.get_field_data_out() >>> field_data_in = solver.get_field_data_in()
dtmm.tmm
¶
4x4 transfer matrix and 2x2 scattering matrix method functions for 1D calculation.
The implementation is based on standard formulation of 4x4 transfer matrix method.
Layers are stacked in the z direction, field vectors describing the field are f = (Ex,Hy,Ey,Hx), Core functionality is defined by field matrix calculation functions:
avec()
for amplitude vector (eigenmode amplitudes).fvec()
for field vector creation,avec2fvec()
for amplitude to field conversion.fvec2avec()
for field to amplitude conversion.
f_iso()
for input and output field matrix calculation.ffi_iso()
besides field matrix, computes also the inverse of the field matrix.alphaf()
for general field vectors and field coefficents calculation (eigensystem calculation).alphaffi()
computes also the inverse of the field matrix.phase_mat()
for phase matrix calculation.
layer_mat()
for layer matrix calculation Mi=Fi.Pi.Fi^-1stack_mat()
for stack matrix caluclation M = M1.M2.M3….system_mat()
for system matrix calculation Fin^-1.M.Fout
transmit4x4()
to work with the computed system matrixtransfer4x4()
ortransfer()
for higher level interface
poynting()
the z component of the Poynting vector.intensity()
the absolute value of the Poytning vector.EHz()
for calculation of the z component of the E and H fields.
todo..
Module Contents¶
-
dtmm.tmm.
alphaf
(beta=None, phi=None, epsv=None, epsa=None, out=None)¶ Computes alpha and field arrays (eigen values and eigen vectors arrays).
Broadcasting rules apply.
- Parameters
beta (float, optional) – The beta parameter of the field (defaults to 0.)
phi (float, optional) – The phi parameter of the field (defaults to 0.)
epsv ((..,3) array, optional) – Dielectric tensor eigenvalues array (defaults to unity).
epsa ((..,3) array, optional) – Euler rotation angles (psi, theta, phi) (defaults to (0.,0.,0.)).
out ((ndarray,ndarray), optional) – Output arrays.
- Returns
alpha, fieldmat – Eigen values and eigen vectors arrays.
- Return type
(ndarray, ndarray)
-
dtmm.tmm.
alphaffi
(beta=None, phi=None, epsv=None, epsa=None, out=None)¶ Computes alpha and field arrays (eigen values and eigen vectors arrays) and inverse of the field array. See also
alphaf()
Broadcasting rules apply.
- Parameters
beta (float, optional) – The beta parameter of the field (defaults to 0.)
phi (float, optional) – The phi parameter of the field (defaults to 0.)
epsv ((..,3) array, optional) – Dielectric tensor eigenvalues array (defaults to unity).
epsa ((..,3) array, optional) – Euler rotation angles (psi, theta, phi) (defaults to (0.,0.,0.)).
out ((ndarray,ndarray,ndarray), optional) – Output arrays.
- Returns
alpha, field, ifield – Eigen values and eigen vectors arrays and its inverse
- Return type
(ndarray, ndarray, ndarray)
Examples
This is equivalent to
>>> alpha,field = alphaf(0,0, [2,2,2], [0.,0.,0.]) >>> ifield = inv(field)
-
dtmm.tmm.
phase_mat
(alpha, kd, mode=None, out=None)¶ Computes a 4x4 or 2x2 diagonal matrix from eigenvalue matrix alpha and wavenumber.
The output is a diagonal, that is, a vector of length 2 or 4, depending on the input alpha array.
Broadcasting rules apply to all arguments, except mode.
- Parameters
alpha (array) – The eigenvalue alpha array of shape (…,4) or (…,2).
kd (float) – The kd phase value (layer thickness times wavenumber in vacuum).
mode (int, optional) – If specified, converts the phase matrix to 2x2, taking either forward propagating mode (+1), or negative propagating mode (-1).
out (ndarray, optional) – Output array where results are written.
- Returns
diag – Phase diagonal matrix of shape (…,4) or (…,2).
- Return type
array
-
dtmm.tmm.
poynting
(fvec, out)¶ Calculates a z-component of the poynting vector from the field vector
- Parameters
fvec ((..,4,4) array) – Field matrix array.
out (ndarray, optional) – Output array where results are written.
Results –
------- –
poynting (array) – The z component of the poynting vector.
-
dtmm.tmm.
intensity
(fvec, out=None)¶ Calculates absolute value of the z-component of the poynting vector
- Parameters
fvec ((..,4) array) – Field vector array.
out (ndarray, optional) – Output array where results are written.
-
dtmm.tmm.
EHz
(fvec, beta=None, phi=None, epsv=None, epsa=None, out=None)¶ Constructs the z component of the electric and magnetic fields.
Broadcasting rules apply.
- Parameters
fvec ((..,4,4) array) – Field matrix array.
beta (float, optional) – The beta parameter of the field (defaults to 0.)
phi (float, optional) – The phi parameter of the field (defaults to 0.)
epsv ((..,3) array, optional) – Dielectric tensor eigenvalues array (defaults to unity).
epsa ((..,3) array, optional) – Euler rotation angles (psi, theta, phi) (defaults to (0.,0.,0.)).
out ((ndarray,ndarray), optional) – Output arrays where results are written.
- Returns
Ez,Hz – Ez and Hz arrays of shape (…,4)
- Return type
(ndarray,ndarray)
-
dtmm.tmm.
f_iso
(beta=0.0, phi=0.0, n=1.0)¶ Returns field matrix for isotropic layer of a given refractive index and beta, phi parameters
Broadcasting rules apply to all arguments, except n
- Parameters
beta (float, optional) – The beta parameter of the field (defaults to 0.)
phi (float, optional) – The phi parameter of the field (defaults to 0.)
n (float) – Refractive index of the medium (1. by default).
-
dtmm.tmm.
ffi_iso
(beta=0.0, phi=0.0, n=1)¶ Returns field matrix and inverse of the field matrix for isotropic layer of a given refractive index and beta, phi parameters.
Broadcasting rules apply to all arguments, except n
- Parameters
beta (float, optional) – The beta parameter of the field (defaults to 0.)
phi (float, optional) – The phi parameter of the field (defaults to 0.)
n (float) – Refractive index of the medium (1. by default).
-
dtmm.tmm.
layer_mat
(kd, epsv, epsa, beta=0, phi=0, cfact=0.1, method='4x4', fmatin=None, retfmat=False, out=None)¶ Computes characteristic matrix of a single layer M=F.P.Fi,
Numpy broadcasting rules apply.
- Parameters
kd (float) – The kd phase value (layer thickness times wavenumber in vacuum).
epsv ((..,3) array, optional) – Dielectric tensor eigenvalues array (defaults to unity).
epsa ((..,3) array, optional) – Euler rotation angles (psi, theta, phi) (defaults to (0.,0.,0.)).
beta (float, optional) – The beta parameter of the field (defaults to 0.)
phi (float, optional) – The phi parameter of the field (defaults to 0.)
cfact (float, optional) – Coherence factor, only used in combination with 4x4_2 method.
method (str) – One of 4x4 (4x4 berreman - trasnmittance + reflectance), 2x2 (2x2 jones - transmittance only), 4x4_1 (4x4, single reflections - transmittance only), 2x2_1 (2x2, single reflections - transmittance only) 4x4_2 (4x4, partially coherent reflections - transmittance only)
fmatin (ndarray, optional) – Used in combination with 2x2_1 method. It specifies the field matrix of the input media in order to compute fresnel reflections. If not provided it reverts to 2x2 with no reflections.
out (ndarray, optional) –
- Returns
cmat – Characteristic matrix of the layer.
- Return type
ndarray
-
dtmm.tmm.
stack_mat
(kd, epsv, epsa, beta=0, phi=0, cfact=0.01, method='4x4', out=None)¶ Computes a stack characteristic matrix M = M_1.M_2….M_n if method is 4x4, 4x2(2x4) and a characteristic matrix M = M_n…M_2.M_1 if method is 2x2.
Note that this function calls
layer_mat()
, so numpy broadcasting rules apply to kd[i], epsv[i], epsa[i], beta and phi.- Parameters
kd (array of floats) – A sequence of phase values (layer thickness times wavenumber in vacuum). len(kd) must match len(epsv) and len(epsa).
epsv ((..,3) array, optional) – Dielectric tensor eigenvalues array (defaults to unity).
epsa ((..,3) array, optional) – Euler rotation angles (psi, theta, phi) (defaults to (0.,0.,0.)).
beta (float, optional) – The beta parameter of the field (defaults to 0.)
phi (float, optional) – The phi parameter of the field (defaults to 0.)
cfact (float) – Coherence factor, only used in combination with 4x4_r and 4x4_2 methods.
method (str) – One of 4x4 (4x4 berreman), 2x2 (2x2 jones), 4x4_1 (4x4, single reflections - transmittance only), 2x2_1 (2x2, single reflections), 4x4_2 (4x4, incoherent reflections - transmittance only)
out (ndarray, optional) –
- Returns
cmat – Characteristic matrix of the stack.
- Return type
ndarray
-
dtmm.tmm.
system_mat
(cmat=None, fmatin=None, fmatout=None, fmatini=None, out=None)¶ Computes a system matrix from a characteristic matrix Fin-1.C.Fout
- Parameters
cmat ((..,4,4) array) – Characteristic matrix.
fmatin ((..,4,4) array) – Input field matrix array.
fmatout ((..,4,4) array) – Output field matrix array.
fmatini ((..,4,4) array) – Inverse of the input field matrix array.
out (ndarray, optional) – Output array where results are written.
-
dtmm.tmm.
reflect
(fvecin, rmat, fmatin=None, fmatout=None, fmatini=None, fmatouti=None, fvecout=None)¶ Reflects/Transmits field vector using 4x4 reflection matrix.
This functions takes a field vector that describes the input field and computes the output transmited field and also updates the input field with the reflected waves.
- Parameters
fvecin ((..,4) array) – Input field vector array. This function will update the input array with the calculated reflected field
rmat ((..,4,4) array) – Reflection matrix.
fmatin ((..,4,4) array) – Input field matrix array.
fmatout ((..,4,4) array) – Output field matrix array.
fmatini ((..,4,4) array) – Inverse of the input field matrix array.
fmatouti ((..,4,4) array, optional) – Inverse of the output field matrix array. If not provided, it is computed from fmatout.
fvecout ((..,4) array, optional) – The ouptut field vector array. This function will update the output array with the calculated transmitted field.
-
dtmm.tmm.
transfer4x4
(fvecin, kd, epsv, epsa, beta=0.0, phi=0.0, nin=1.0, nout=1.0, method='4x4', reflect_in=False, reflect_out=False, fvecout=None)¶ Tranfers field using 4x4 method.
see also
transfer()
- Parameters
fvecin ((..,4) array) – Input field vector array. This function will update the input array with the calculated reflected field
kd (array of floats) – A sequence of phase values (layer thickness times wavenumber in vacuum). len(kd) must match len(epsv) and len(epsa).
epsv ((..,3) array, optional) – Dielectric tensor eigenvalues array (defaults to unity).
epsa ((..,3) array, optional) – Euler rotation angles (psi, theta, phi) (defaults to (0.,0.,0.)).
beta (float, optional) – The beta parameter of the field (defaults to 0.)
phi (float, optional) – The phi parameter of the field (defaults to 0.)
nin (float) – Input layer refractive index.
nout (float) – Output layer refractive index.
method (str) – Any of 4x4, 4x4_1, 4x4_2.
fvecout ((..,4) array, optional) – The ouptut field vector array. This function will update the output array with the calculated transmitted field.
-
dtmm.tmm.
transfer2x2
(evec, kd, epsv, epsa, beta=0.0, phi=0.0, nin=None, nout=None, method='2x2', out=None)¶ Tranfers E-vec using 2x2 scattering matrices.
- Parameters
evec ((..,2) array) – Input E-field vector array. This function will update the input array with the calculated reflected field
kd (array of floats) – A sequence of phase values (layer thickness times wavenumber in vacuum). len(kd) must match len(epsv) and len(epsa).
epsv ((..,3) array, optional) – Dielectric tensor eigenvalues array (defaults to unity).
epsa ((..,3) array, optional) – Euler rotation angles (psi, theta, phi) (defaults to (0.,0.,0.)).
beta (float, optional) – The beta parameter of the field (defaults to 0.)
phi (float, optional) – The phi parameter of the field (defaults to 0.)
nin (float) – Input layer refractive index.
nout (float) – Output layer refractive index.
method (str) – Any of 2x2, 2x2_1.
out ((..,2) array, optional) – The ouptut field vector array. This function will update the output array with the calculated transmitted field.
-
dtmm.tmm.
transfer
(fvecin, kd, epsv, epsa, beta=0.0, phi=0.0, nin=1.0, nout=1.0, method='2x2', reflect_in=False, reflect_out=False, fvecout=None)¶ Transfer input field vector through a layered material specified by the propagation constand k*d, eps tensor (epsv, epsa) and input and output isotropic media.
- Parameters
fvecin ((..,4) array) – Input field vector array. This function will update the input array with the calculated reflected field
kd (array of floats) – A sequence of phase values (layer thickness times wavenumber in vacuum). len(kd) must match len(epsv) and len(epsa).
epsv ((..,3) array, optional) – Dielectric tensor eigenvalues array (defaults to unity).
epsa ((..,3) array, optional) – Euler rotation angles (psi, theta, phi) (defaults to (0.,0.,0.)).
beta (float, optional) – The beta parameter of the field (defaults to 0.)
phi (float, optional) – The phi parameter of the field (defaults to 0.)
nin (float) – Input layer refractive index.
nout (float) – Output layer refractive index.
method (str) – Any of 4x4, 2x2, 2x2_1 or 4x4_1, 4x4_2, 4x4_r
reflect_in (bool) – Defines how to treat reflections from the input media and the first layer. If specified it does an incoherent reflection from the first interface.
reflect_out (bool) – Defines how to treat reflections from the last layer and the output media. If specified it does an incoherent reflection from the last interface.
fvecout ((..,4) array, optional) – The ouptut field vector array. This function will update the output array with the calculated transmitted field.
-
dtmm.tmm.
avec
(jones=(1, 0), amplitude=1.0, mode=+ 1, out=None)¶ Constructs amplitude vector.
Numpy broadcasting rules apply for jones, and amplitude parameters
- Parameters
jones (jonesvec) – A jones vector, describing the polarization state of the field.
amplitude (complex) – Amplitude of the field.
mode (int) – Either +1, for forward propagating mode, or -1 for negative propagating mode.
out (ndarray, optional) – Output array where results are written.
- Returns
avec – Amplitude vector of shape (4,).
- Return type
ndarray
Examples
X polarized light with amplitude = 1 >>> avec() array([1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j])
X polarized light with amplitude 1 and y polarized light with amplitude 2. >>> b = avec(jones = ((1,0),(0,1)),amplitude = (1,2)) >>> b[0] array([1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]) >>> b[1] array([0.+0.j, 0.+0.j, 2.+0.j, 0.+0.j])
-
dtmm.tmm.
fvec
(fmat, jones=(1, 0), amplitude=1.0, mode=+ 1, out=None)¶ Build field vector form a given polarization state, amplitude and mode.
This function calls avec and then avec2fvec, see avec for details.
- Parameters
fmat ((..,4,4) array) – Field matrix array.
jones (jonesvec) – A jones vector, describing the polarization state of the field.
amplitude (complex) – Amplitude of the field.
mode (int) – Either +1, for forward propagating mode, or -1 for negative propagating mode.
out (ndarray, optional) – Output array where results are written.
- Returns
fvec – Field vector of shape (…,4).
- Return type
ndarray
Examples
X polarized light traveling at beta = 0.4 and phi = 0.2 in medium with n = 1.5
>>> fmat = f_iso(beta = 0.4, phi = 0.2, n = 1.5) >>> m = fvec(fmat, jones = jonesvec((1,0), phi = 0.2))
This is equivalent to
>>> a = avec(jones = jonesvec((1,0), phi = 0.2)) >>> ma = avec2fvec(a,fmat) >>> np.allclose(ma,m) True
-
dtmm.tmm.
fvec2avec
(fvec, fmat, normalize_fmat=True, out=None)¶ Converts field vector to amplitude vector
- Parameters
fvec (ndarray) – Input field vector
fmat (ndarray) – Field matrix
normalize_fmat (bool, optional) – Setting this to false will not normalize the field matrix. In this case user has to make sure that the normalization of the field matrix has been performed prior to calling this function by calling normalize_f.
out (ndarray, optional) – Output array
- Returns
avec – Amplitude vector
- Return type
ndarray
-
dtmm.tmm.
avec2fvec
(avec, fmat, normalize_fmat=True, out=None)¶ Converts amplitude vector to field vector
- Parameters
avec (ndarray) – Input amplitude vector
fmat (ndarray) – Field matrix
normalize_fmat (bool, optional) – Setting this to false will not normalize the field matrix. In this case user has to make sure that the normalization of the field matrix has been performed prior to calling this function by calling normalize_f.
out (ndarray, optional) – Output array
- Returns
fvec – Field vector.
- Return type
ndarray
dtmm.tmm2d
¶
4x4 transfer matrix method functions for 2d data. It can be used to transfer 2d plane waves over 2d or 1d data.
Module Contents¶
-
dtmm.tmm2d.
layer_mat2d
(k0, d, epsv, epsa, mask=None, method='4x4', betay=0.0, swap_axes=False, resolution_power=0)¶ Computes characteristic matrix of a single layer M=F.P.Fi,
Numpy broadcasting rules apply.
- Parameters
k0 (float or sequence of floats) – A scalar or a vector of wavenumbers
d (array_like) – Layer thickness
epsv (ndarray) – Epsilon eigenvalues.
epsa (ndarray) – Optical axes orientation angles (psi, theta, phi).
method (str, optional) – Either ‘4x4’ (default), ‘4x4_1’, or ‘2x2’.
- Returns
cmat – Characteristic matrix of the layer.
- Return type
ndarray
-
dtmm.tmm2d.
system_mat2d
(cmat=None, fmatin=None, fmatout=None)¶ Computes a system matrix from a characteristic matrix Fin-1.C.Fout
-
dtmm.tmm2d.
reflect2d
(fvecin, rmat, fmatin, fmatout, fvecout=None)¶ Transmits/reflects field vector using 4x4 method.
This functions takes a field vector that describes the input field and computes the output transmited field vector and also updates the input field with the reflected waves.
dtmm.tmm3d
¶
4x4 and 2x2 transfer matrix method functions for 3d calculation.
Module Contents¶
-
dtmm.tmm3d.
split_mask3d
(mask, shape)¶ For 2d or 3d data, given the material shape, it splits input mask into a list of masks. For 1d data no change is made.
-
dtmm.tmm3d.
layer_mat3d
(k0, d, epsv, epsa, mask=None, method='4x4', resolution_power=0)¶ Computes characteristic matrix of a single layer M=F.P.Fi,
Numpy broadcasting rules apply.
- Parameters
k0 (float or sequence of floats) – A scalar or a vector of wavenumbers
d (array_like) – Layer thickness
epsv (array_like) – Epsilon eigenvalues.
epsa (array_like) – Optical axes orientation angles (psi, theta, phi).
method (str, optional) – Either ‘4x4’ (default), ‘4x4_1’, or ‘2x2’.
- Returns
cmat – Characteristic matrix of the layer.
- Return type
ndarray
-
dtmm.tmm3d.
upscale1
(mat, mask)¶ Upscales 1d matrix to 2d matrix
-
dtmm.tmm3d.
upscale2
(mat, mask)¶ Upscales 2d matrix to 3d matrix
-
dtmm.tmm3d.
fmat3d
(fmat)¶ Converts a sequence of 4x4 matrices to a single large matrix
-
dtmm.tmm3d.
system_mat3d
(cmat=None, fmatin=None, fmatout=None)¶ Computes a system matrix from a characteristic matrix Fin-1.C.Fout
-
dtmm.tmm3d.
reflect3d
(fvecin, rmat, fmatin, fmatout, fvecout=None)¶ Transmits/reflects field vector using 4x4 method.
This functions takes a field vector that describes the input field and computes the output transmited field vector and also updates the input field with the reflected waves.
-
dtmm.tmm3d.
transmit3d
(fvecin, tmat, fmatin, fmatout, fvecout=None)¶ Transmits/reflects field vector using 4x4 method.
This functions takes a field vector that describes the input field and computes the output transmited field vector and also updates the input field with the reflected waves.
dtmm.transfer
¶
Main top level calculation functions for light propagation through optical data.
Module Contents¶
-
dtmm.transfer.
total_intensity
(field)¶ Calculates total intensity of the field. Computes intesity and sums over pixels.
-
dtmm.transfer.
transmitted_field
(field, wavenumbers, n=1, betamax=None, out=None)¶ Computes transmitted (forward propagating) part of the field.
- Parameters
field (ndarray) – Input field array
wavenumbers (array_like) – Wavenumbers of the field
n (float, optional) – Refractive index of the media (1 by default)
betamax (float, optional) – Betamax perameter used. If not specified, default value is read from DTMMConf.
out (ndarray, optinal) – Output array
- Returns
out – Transmitted field.
- Return type
ndarray
-
dtmm.transfer.
reflected_field
(field, wavenumbers, n=1, betamax=None, out=None)¶ Computes reflected (backward propagating) part of the field.
- Parameters
field (ndarray) – Input field array
wavenumbers (array_like) – Wavenumbers of the field
n (float, optional) – Refractive index of the media (1 by default)
betamax (float, optional) – Betamax perameter used. If not specified, default value is read from DTMMConf.
norm (bool, optional) – Whether to normalize field so that power spectrum of the output field remains the same as that of the input field.
out (ndarray, optinal) – Output array
- Returns
out – Reflected field.
- Return type
ndarray
-
dtmm.transfer.
transfer_field
(field_data, optical_data, beta=None, phi=None, nin=None, nout=None, npass=None, nstep=1, diffraction=None, reflection=None, method=None, multiray=False, norm=DTMM_NORM_FFT, betamax=None, smooth=SMOOTH, split_rays=False, split_diffraction=False, split_wavelengths=False, split_layers=False, create_matrix=False, eff_data=None, ret_bulk=False, out=None)¶ Tranfers input field data through optical data.
This function calculates transmitted field and possibly (when npass > 1) updates input field with reflected waves.
- Parameters
field_data (Field data tuple) – Input field data tuple
optical_data (Optical data tuple) – Optical data tuple through which input field is transfered.
beta (float or 1D array_like of floats, optional) – Beta parameter of the input field. If it is a 1D array, beta[i] is the beta parameter of the field_data[0][i] field array.f not provided, beta is caluclated from input data (see also multiray option).
phi (float or 1D array_like of floats, optional) – Phi angle of the input light field. If it is a 1D array, phi[i] is the phi parameter of the field_data[0][i] field array. If not provided, phi is caluclated from input data (see also multiray option).
nin (float, optional) – Refractive index of the input (bottom) surface (1. by default). Used in combination with npass > 1 to determine reflections from input layer, or in combination with reflection = True to include Fresnel reflection from the input surface.
nout (float, optional) – Refractive index of the output (top) surface (1. by default). Used in combination with npass > 1 to determine reflections from output layer, or in combination with reflection = True to include Fresnel reflection from the output surface.
npass (int, optional) – How many passes (iterations) to perform. For strongly reflecting elements this should be set to a higher value. If npass > 1, then input field data is overwritten and adds reflected light from the sample (defaults to 1).
nstep (int or 1D array_like of ints) – Specifies layer propagation computation steps (defaults to 1). For thick layers you may want to increase this number. If layer thickness is greater than pixel size, you should increase this number.
diffraction (bool or int, optional) – Defines how diffraction is calculated. Setting this to False or 0 will disable diffraction calculation. Diffraction is enabled by default. If specified as an integer, it defines diffraction calculation quality. 1 for simple (fast) calculation, higher numbers increase accuracy and decrease computation speed. You can set it to np.inf or -1 for max (full) diffraction calculation and very slow computation.
reflection (bool or int or None, optional) – Reflection calculation mode for ‘2x2’ method. It can be either 0 or False for no reflections, 1 (default) for reflections in fft space (from effective layers), or 2 for reflections in real space (from individual layers). If this argument is not provided it is automatically set to 0 if npass == 1 and 1 if npass > 1 and diffraction == 1 and to 2 if npass > 1 and diffraction > 1. See documentation for details.
method (str, optional) – Specifies which method to use, either ‘2x2’ (default) or ‘4x4’. The “4x4” mathod is not yet fully supported. Some options may not work when set to the 4x4 method. The “4x4” method is still considered experimental, so you should generally use “2x2”, and only try “4x4” method if “2x2” fails to converge in multi-pass simulations.
multiray (bool) – If specified it defines if first axis of the input data is treated as multiray data or not. If beta and phi are not set, you must define this if your data is multiray so that beta and phi values are correctly determined.
norm (int, optional) – Normalization mode used when calculating multiple reflections with npass > 1 and 4x4 method. Possible values are 0, 1, 2, default value is 1.
betamax (float, optional) – Betamax perameter used. If not specified, default value is read from DTMMConf.
smooth (float, optional) – Smoothing parameter when calculating multiple reflections with npass > 1 and 4x4 method. Possible values are values above 0.Setting this to higher values > 1 removes noise but reduces convergence speed. Setting this to < 0.1 increases convergence, but it increases noise.
split_rays (bool, optional) – In multi-ray computation this option specifies whether to split computation over single rays to consume less temporary memory storage. For large multi-ray datasets this option should be set.
split_diffraction (bool, optional) – In diffraction > 1 calculation this option specifies whether to split computation over single beam to consume less temporary memory storage. For large diffraction values this option should be set.
split_wavelengths (bool, optional) – Specifies whether to treat data at each wavelength as an independent ray. With off-axis propagation of eigenmodes with different beta values this should be set to true to assure proper determination of beta parameter for proper reflection calculation. Normally there will be very little difference, however, for small simulation volumes (compared to the wavelength) and at large incidence angles, you should set this to True for simulations of multi-wavelength fields. For dispersive material, this option must be set to True.
split_layers (bool, optional) – Specifieas whether to split layers. This affects how the diffraction propagation step, which is block-specific, handles the effective data. With split_layers set, each layer in the stack gets its own diffraction matrix, based on the effective parameters of the layer. This argument calls the
data.layered_data()
. This also affects the eff_data argument.create_matrix (int, optional) – Either 0,1,2. Defines whether to compute transfer matrices for each of the block rather than performing field propagation. Setting this to 1 will force creation of matrices for 1d layer only. Setting this to 2 will force creation of matrices for 1d and 2d layers. Currently, supported in 2x2 method only.
eff_data (list or symmetry, optional) – Optical data list of homogeneous layers through which light is diffracted in the diffraction calculation when diffraction >= 1. If not provided, an effective data is build from optical_data by taking the mean value of the epsilon tensor. You can also provide the symmetry argument, e.g. ‘isotropic’, ‘uniaxial’ or ‘biaxial’, or a list of these values specifying the symmetry of each of the blocks. This argument is passed directly to the
data.effective_data()
function.ret_bulk (bool, optional) – Whether to return bulk field instead of the transfered field (default).
out (ndarray, optional) – Output array.
- Returns
field_out – If ret_bulk is False it returns a field data tuple. If ret_bulk is True it returns a list of field data tuples. Each element of the list represents bulk data for each of the blocks.
- Return type
tuple or list
-
dtmm.transfer.
transfer_4x4
(field_data, optical_data, beta=0.0, phi=0.0, eff_data=None, nin=1.0, nout=1.0, npass=1, nstep=1, diffraction=True, reflection=1, multiray=False, norm=DTMM_NORM_FFT, smooth=SMOOTH, betamax=None, ret_bulk=False, out=None)¶ Transfers input field data through optical data. See transfer_field.
-
dtmm.transfer.
transfer_2x2
(field_data, optical_data, beta=None, phi=None, eff_data=None, nin=1.0, nout=1.0, npass=1, nstep=1, diffraction=True, reflection=True, multiray=False, split_diffraction=False, betamax=None, ret_bulk=False, create_matrix=0, out=None)¶ Tranfers input field data through optical data using the 2x2 field matrices. Optionally, it can create 2x2 or 4x4 transfer matrices, depending on the. See transfer_field for documentation.
You should use
transfer_field()
instead of this.
dtmm.wave
¶
Wave creation and wave characterization functions.
Core functions¶
betaphi()
computes beta and phi arrays of the eigenmodes.betaxy()
computes betax and betay arrays of the eigenmodes.eigenbeta()
returns beta eigenvalue array(s).eigenindices()
returns indices array(s) of all valid eigenwaves.eigenphi()
returns phi eigenvalue array(s).eigenmask()
returns a mask array(s) of all valid egenwaves.eigenwave()
returns eigenwave array.k0()
computes wave number from wavelength.planewave()
returns planewave array.wavelengths()
returns wavelengths equaly spaced in wave numbers.
Conversion functions¶
betaxy2beta()
converts betax, betay arrays to beta array.betaxy2phi()
converts betax, betay arrays to phi array.betaxy2betaphi()
converts betax, betay arrays to beta, phi arrays.betaphi2betax()
converts beta, phi arrays to betax array.betaphi2betay()
converts beta, phi arrays to betay array.betaphi2betaxy()
converts beta, phi arrays to betax, betay arrays.mask2beta()
converts mask array to beta array(s).mask2phi()
converts mask array to phi array(s).mask2indices()
converts mask array to indices array(s).wave2eigenwave()
converts any plane wave to nearest eigenwave.
1D functions¶
1D waves and conversion functions (for 2D simulations)
betax1()
computes betax and betay arrays of the eigenmodes.eigenbeta1()
returns beta eigenvalue array(s).eigenindices1()
returns indices array(s) of all valid eigenwaves.eigenmask1()
returns a mask array(s) of all valid egenwaves.eigenwave1()
returns eigenwave array.mask2beta1()
converts mask array to beta array(s).mask2indices1()
converts mask array to indices array(s).planewave1()
returns planewave array.
Module Contents¶
-
dtmm.wave.
betaphi
(shape, k0, out=None)¶ Returns beta and phi arrays of all possible plane eigenwaves.
- Parameters
shape ((int,int)) – Shape (height, width) of the plane eigenwave.
k0 (float or array of floats) – Wavenumber (or wavenumbers) in pixel units.
out ((ndarray, ndarray), optional) – Output arrays tuple.
- Returns
out – beta, phi arrays. The shape of the outputs is beta, phi: (height,width) or beta: (len(k0),height,width) if k0 is an array.
- Return type
array, array
-
dtmm.wave.
betaxy
(shape, k0, out=None)¶ Returns betax, betay arrays of plane eigenwaves.
- Parameters
shape ((int,int)) – Shape (height, width) of the plane eigenwave.
k0 (float or array of floats) – Wavenumber (or wavenumbers) in pixel units.
out ((ndarray, ndarray), optional) – Output arrays tuple.
- Returns
out – beta, phi arrays
- Return type
array, array
-
dtmm.wave.
betaxy2betaphi
(betax, betay)¶ Converts betax, betay arrays to beta, phi arrays.
-
dtmm.wave.
betaxy2beta
(betax, betay)¶ Converts betax, betay arrays to beta array
-
dtmm.wave.
betaxy2phi
(betax, betay)¶ Converts betax, betay arrays to phi array
-
dtmm.wave.
betaphi2betaxy
(beta, phi)¶ Converts beta, phi arrays to betax, betay arrays.
-
dtmm.wave.
betaphi2betax
(beta, phi)¶ Converts beta, phi arrays to betax array.
-
dtmm.wave.
betaphi2betay
(beta, phi)¶ Converts beta, phi arrays to betay array.
-
dtmm.wave.
eigenwave
(shape, i, j, amplitude=None, out=None)¶ Returns a planewave with a given fourier coefficient indices i and j.
- Parameters
shape ((..,int,int)) – Shape (height, width) of the plane eigenwave.
i (int) – i-th index of the fourier coefficient
j (float) – j-th index of the fourier coefficient
amplitude (complex, optional) – Amplitude of the fourier mode. If not specified it is set so that the amplitude in real space equals one.
out (ndarray, optional) – Output array.
- Returns
out – Plane wave array of shape (…,height,width).
- Return type
array
-
dtmm.wave.
eigenbeta
(shape, k0, betamax=None)¶ Returns masked beta array(s) of all valid eigenwaves.
- Parameters
shape ((int,int)) – Shape (height, width) of the plane eigenwave.
k0 (float or array of floats) – Wavenumber (or wavenumbers) in pixel units.
betamax (float, optional) – The cutoff beta value. If not specified, it is set to default.
- Returns
out – Masked beta array(s).
- Return type
ndarray or tuple of ndarrays.
-
dtmm.wave.
eigenindices
(shape, k0, betamax=None)¶ Returns masked indices array(s) of all valid eigenwaves.
- Parameters
shape ((int,int)) – Shape (height, width) of the plane eigenwave.
k0 (float or array of floats) – Wavenumber (or wavenumbers) in pixel units.
betamax (float, optional) – The cutoff beta value. If not specified, it is set to default.
- Returns
out – Masked indices array(s).
- Return type
ndarray or tuple of ndarrays.
-
dtmm.wave.
eigenphi
(shape, k0, betamax=None)¶ Returns masked phi array(s) of all valid eigenwaves.
- Parameters
shape ((int,int)) – Shape (height, width) of the plane eigenwave.
k0 (float or array of floats) – Wavenumber (or wavenumbers) in pixel units.
betamax (float, optional) – The cutoff beta value. If not specified, it is set to default.
- Returns
out – Masked phi array(s).
- Return type
ndarray or tuple of ndarrays.
-
dtmm.wave.
eigenmask
(shape, k0, betamax=None)¶ Returns a boolean array of valid modal coefficents.
Valid coefficients are those that have beta <= betamax.
- Parameters
shape ((int,int)) – Shape (height, width) of the plane eigenwave.
k0 (float or array of floats) – Wavenumber (or wavenumbers) in pixel units.
betamax (float, optional) – The cutoff beta value. If not specified, it is set to default.
- Returns
mask – A boolean array of shape (height, width) or (len(k0), height, width).
- Return type
ndarray
-
dtmm.wave.
k0
(wavelength, pixelsize=1.0)¶ Calculate wave number in vacuum from a given wavelength and pixelsize
- Parameters
wavelength (float or array of floats) – Wavelength in nm
pixelsize (float) – Pixelsize in nm
- Returns
out – Wavenumber array
- Return type
array
-
dtmm.wave.
mask2beta
(mask, k0)¶ Converts the input mask array to a masked beta array(s).
- Parameters
mask (ndarray) – A mask array of shape (n,height,width) or (height,width). If it is a 3D array the first axis must match the length of k0.
k0 (float or array of floats) – Wavenumber (or wavenumbers if mask.ndim = 3) in pixel units.
- Returns
beta – Array(s) of maksed beta values.
- Return type
ndarray or tuple of ndarrays
-
dtmm.wave.
mask2phi
(mask, k0)¶ Converts the input mask array to a masked phi array(s).
- Parameters
mask (ndarray) – A mask array of shape (n,height,width) or (height,width). If it is a 3D array the first axis must match the length of k0.
k0 (float or array of floats) – Wavenumber (or wavenumbers if mask.ndim = 3) in pixel units.
- Returns
beta – Array(s) of maksed phi values.
- Return type
ndarray or tuple of ndarrays
-
dtmm.wave.
mask2indices
(mask, k0=None)¶ Converts the input mask array to a masked indices array(s).
- Parameters
mask (ndarray) – A mask array of shape (n,height,width) or (height,width).
- Returns
beta – Array(s) of maksed indices values.
- Return type
ndarray or tuple of ndarrays
-
dtmm.wave.
planewave
(shape, k0, beta, phi, out=None)¶ Returns a 2D planewave array with a given beta, phi, wave number k0.
Broadcasting rules apply.
- Parameters
shape ((int,int)) – Shape (height, width) of the plane eigenwave.
k0 (float or floats array) – Wavenumber in pixel units.
beta (float or floats array) – Beta parameter of the plane wave
phi (float or floats array) – Phi parameter of the plane wave
out ((ndarray, ndarray), optional) – Output arrays tuple
- Returns
Plane wave array.
- Return type
array
-
dtmm.wave.
wavelengths
(start=380, stop=780, count=9)¶ Raturns wavelengths (in nanometers) equaly spaced in wavenumbers between start and stop.
- Parameters
start (float) – First wavelength
stop (float) – Last wavelength
count (int) – How many wavelengths
- Returns
out – A wavelength array
- Return type
ndarray
-
dtmm.wave.
wave2eigenwave
(wave, out=None)¶ Converts any 2D wave to nearest eigenwave.
- Parameters
wave (ndarray) – Input 2D plane wave.
out (ndarray, optional) – Ouptut array.
- Returns
out – Nearest eigenwave array.
- Return type
ndarray
-
dtmm.wave.
eigenwave1
(n, i, amplitude=None)¶ Returns a 1D eigenwave with a given fourier coefficient indices i.
- Parameters
n (int) – Shape of the plane eigenwave.
i (int) – i-th index of the fourier coefficient
amplitude (complex) – Amplitude of the fourier mode.
out (ndarray, optional) – Output array
- Returns
out – Plane wave array.
- Return type
array
-
dtmm.wave.
betax1
(n, k0, out=None)¶ Returns 1D beta values of all possible 1D eigenwaves.
- Parameters
n (int) – Shape of the planewave.
k0 (float or array of floats) – Wavenumber in pixel units.
out (ndarray, optional) – Output arrays tuple
- Returns
out – beta array.
- Return type
array
-
dtmm.wave.
eigenmask1
(n, k0, betay=0, betamax=None)¶ Returns a boolean array of valid modal coefficents of 1D waves.
Valid coefficients are those that have beta <= betamax.
- Parameters
n (int) – Shape of the 1D eigenwave.
k0 (float or array of floats) – Wavenumber (or wavenumbers) in pixel units.
betay (float or array) – The betay parameter of the eigenwave. If set as an array, it should broadcast with k0.
betamax (float, optional) – The cutoff beta value. If not specified, it is set to default.
- Returns
mask – A boolean array of shape (n,) or (len(k0), n).
- Return type
ndarray
-
dtmm.wave.
mask2betax1
(mask, k0)¶ Converts the input mask array to a masked betax array(s).
- Parameters
mask (ndarray) – A mask array of shape (n,height) or (height,). If it is a 2D array the first axis must match the length of k0.
k0 (float or array of floats) – Wavenumber (or wavenumbers) in pixel units.
- Returns
beta – Array(s) of maksed betax values.
- Return type
ndarray or tuple of ndarrays
-
dtmm.wave.
mask2indices1
(mask, k0=None)¶ Converts the input mask array to a masked indices array(s).
- Parameters
mask (ndarray) – A mask array of shape (n,height) or (height,).
- Returns
beta – Array(s) of maksed indices values.
- Return type
ndarray or tuple of ndarrays
-
dtmm.wave.
eigenbetax1
(n, k0, betay=0, betamax=None)¶ Returns masked betax1 array(s) of all valid eigenwaves.
- Parameters
n (int) – Shape of the plane eigenwave.
k0 (float or array of floats) – Wavenumber (or wavenumbers) in pixel units.
betamax (float, optional) – The cutoff beta value. If not specified, it is set to default.
- Returns
out – Masked beta array(s).
- Return type
ndarray or tuple of ndarrays.
-
dtmm.wave.
eigenindices1
(n, k0, betay=0, betamax=None)¶ Returns masked indices array(s) of all valid 1D eigenwaves.
- Parameters
n (int) – Shape of the 1D eigenwave.
k0 (float or array of floats) – Wavenumber (or wavenumbers) in pixel units.
betamax (float, optional) – The cutoff beta value. If not specified, it is set to default.
- Returns
out – Masked indices array(s).
- Return type
ndarray or tuple of ndarrays.
-
dtmm.wave.
planewave1
(n, k0, beta, out=None)¶ Returns a 1D planewave array with a given beta, wave number k0.
- Parameters
n (int) – Shape of the plane eigenwave.
k0 (float or array of floats) – Wavenumbers in pixel units.
beta (float) – Beta parameter of the plane wave
- Returns
Plane wave array.
- Return type
array
dtmm.window
¶
Window functions for input field shaping.
window.aperture()
: Round (circular) aperture function.window.blackman()
: A 2D Blackman window function.window.gaussian()
: A 2D Gaussian window function.window.gaussian_beam()
: A Gaussian beam in paraxial approximation.
Module Contents¶
-
dtmm.window.
blackman
(shape, out=None)¶ Returns a blacman window of a given shape.
- Parameters
shape ((int,int)) – A shape of the 2D window.
out (ndarray, optional) – Output array.
- Returns
window – A Blackman window
- Return type
ndarray
-
dtmm.window.
gaussian
(shape, waist)¶ Gaussian amplitude window function.
- Parameters
shape ((int,int)) – A shape of the 2D window
waist (float) – Waist of the gaussian.
- Returns
window – Gaussian beam window
- Return type
ndarray
-
dtmm.window.
gaussian_beam
(shape, waist, k0, z=0.0, n=1)¶ Returns gaussian beam window function.
- Parameters
shape ((int,int)) – A shape of the 2D window
waist (float) – Waist of the beam
k0 (float) – Wavenumber
z (float, optional) – The z-position of waist (0. by default)
n (float, optional) – Refractive index (1. by default)
out (ndarray, optional) – Output array.
- Returns
window – Gaussian beam window
- Return type
ndarray
-
dtmm.window.
aperture
(shape, diameter=1.0, smooth=0.05, out=None)¶ Returns (annular) aperture window function.
- Parameters
shape ((int,int)) – A shape of the 2D window
diameter (float or (float,float)) – Width of the aperture (1. for max height/width). If set as a tuple of two elements, it describes the inner and outer width of the annular aperture.
smooth (float) – Smoothnes parameter - defines smoothness of the edge of the aperture (should be between 0. and 1.; 0.05 by default)
out (ndarray, optional) – Output array.
- Returns
window – Aperture window
- Return type
ndarray
- 1
Created with sphinx-autoapi