Rigorous Coupled Wave Analysis (S4)¶
Example 1: Comparing optical models (TMM, BeerLambert, and RCWA)
Solcore’s capacity for modelling periodic nanophotonic structures is provided through an interface with the Python extension, an implementation of RCWA (Rigorous Coupled Wave Analysis) developed in the Fan Group in the Stanford Electrical Engineering Department. The documentation for S4 can be found here. The basic mechanics of the RCWA module are:
 Solcore translates the relevant inputs (list) into the appropriate notation for
 Solcore calls and feeds in the relevant inputs
 Solcore translates the outputs from into the relevant outputs, which match the outputs from Solcore’s other optics methods (absorption, reflection, transmission, absorption profile with depth).
To use from within Solcore, first make sure S4 is installed from the custom branch compatible with Python3.
Layers
in the SolarCell
object are defined in the usual Solcore way, but now have an additional geometry
attribute, e.g.:
# define materials
Air = material('Air')(T=T)
TiO2 = material('TiO2', sopra=True)(T=T) # for the nanoparticles
# define a layer with circular discs
NP_layer = [Layer(si('50nm'), Air, geometry=[{'type': 'circle', 'mat': TiO2,
'center': (200, 200), 'radius': 50}])]
The geometry
attribute is a list of dictionaries containing relevant entries. You can add more than one shape
per layer by simply adding more dictionaries to the list; each dictionary defines one shape, which is assumed to be periodic
in two directions. The necessary information to define shapes is:
For all shapes:
 ‘type’: ‘circle’, ‘ellipse’, ‘rectangle’ or ‘polygon’
 ‘mat’: the material the shape is made of; a Solcore material object.
 ‘center’: a tuple giving x and y coordinates (in nm) of the centre of the shape: (x, y)
Additional shapedependent parameters:
 Circle: * ‘radius’: a number in nm
 Ellipse: * ‘angle’: a number in degrees, defining the angle by which the xaxis of the shape should be rotated (counterclockwise). * ‘halfwidths’: a tuple of halfwidths in the x and y directions: (hw_x, hw_y)
 Rectangle: ‘angle’ and ‘halfwidths’, as before
 Polygon: * ‘angle’ as before * ‘vertices’: a tuple of tuples; each entry in the outer tuple are the x and ycoordinates of the vertices of the (unrotated) polygon, one after another, in counterclockwise order, e.g. ((x1, y1), (x2, y2), (x3, y3)). Coordinates are in nm.
Additionally, you should set the lattice vectors u and v defining the unit cell in your user options, and the number of Fourier orders to keep in the calculations in opts.orders:
opts.size = ((400, 0), (0, 400)) # lattice vectors for a square grating with period 400 nm
opts.size = ((400, 0), (400 / 2, np.sin(np.pi / 3) * 400))
# lattice vectors for a grating with hexagonal symmetry (triangular unit cell)
opts.orders = 19 # keep 19 Fourier orders
The calculation should converge for a higher number of orders, but computational time increases dramatically with the number of orders (scaled as the number of orders cubed).
Note that all dimensional information for the size and geometries should be in nm!
The RCWA interface for the solar cell solver¶
This is the method actually called from the solar cell solver, serving as interface between the solar cell and the RCWA formalism. The BeerLambert calculator, TMM calculator and the external optics calculator (where the user simply adds the reflection and the absorption profile manually) have similar interfaces.
The RCWA solver can handle different input angles and polarizations, specified in the options (specifically, options.theta, options.phi and options.pol). Theta is the polar angle while phi is the azimuthal angle clockwise from the yaxis. Both angles are in degrees, while pol is ‘s’, ‘p’ or ‘u’ (computationally, ‘u’ is simply the average of ‘s’ and ‘p’ and thus requires two calculations  therefore it will take twice as long.)

solcore.optics.rcwa.
solve_rcwa
(solar_cell: solcore.solar_cell.SolarCell, wavelength: numpy.ndarray[Any, numpy.dtype[ScalarType]], position: numpy.ndarray[Any, numpy.dtype[ScalarType]], parallel: bool = False, size: Tuple[int, int] = ((500, 500), (500, 500)), orders: int = 4, theta: float = 0, phi: float = 0, pol: str = 'u', n_jobs: int = 1, rcwa_options: Optional[solcore.state.State] = None, **kwargs) → None[source]¶ Calculates the RAT of a solar cell object using the RCWA solver.
The SolarCell object is updated with the wavelength, the calculated reflected, transmitted and absorved ligth. Additionally, each a method to calculate the absorved ligth per junction and the ligth absorved per later are also added to the individual junctions.
 Args:
solar_cell (SolarCell): A solar_cell object wavelength (NDArray): Array of wavelegth at which the optics are calculated. position (NDArray): Array of positions in the z direction to calculate the
absorption vs depth. parallel (bool, optional): whether or not to execute calculation in parallel
 (over wavelengths). Defaults to False.
 size (Tuple[int, int], optional): a tuple of 2D vectors in the format ((ux,
 uy), (vx, vy)) giving the x and y components of the lattice unit vectors in nm. Defaults to ((500, 500), (500, 500)).
 orders (int, optional): number of orders to retain in the RCWA calculations.
 Defaults to 4.
 theta (float, optional): the polar incidence angle, in degrees, with 0 degrees
 being normal incidence. Defaults to 0.
phi (float, optional): azimuthal incidence angle (in degrees). Defaults to 0. pol (str, optional): the polarization of the light (‘s’, ‘p’ or ‘u’). Defaults
to “u”. n_jobs (int, optional): the ‘n_jobs’ argument passed to Parallel from the joblib
 package. If set to 1, all available CPUs are used, if set to 1 no parallel computing is executed. The number of CPUs used is given by n_cpus + 1 + n_jobs. Defaults to 1.
 rcwa_options (Optional[State], optional): dictionary of options for S4. Defaults
to None. The list of possible entries and their values is:
 LatticeTruncation: ‘Circular’ or ‘Parallelogramic’ (default ‘Circular’)
 DiscretizedEpsilon: True or False (default False)
 DiscretizationResolution: integer (default value 8)
 PolarizationDecomposition: True or False (default False)
 PolarizationBasis: ‘Default’ or ‘Normal’ or ‘Jones’ (default ‘Default’)
 LanczosSmoothing: True or False (default False)
 SubpixelSmoothing: True or False (default False)
 ConserveMemory: True or False (default False)
 WeismannFormulation: True or False (default False)
 Return:
 None