Ray-tracing

There are two distinct uses of the ray-tracing code: to create redistribution matrices for the matrix framework, and to define and calculate structures which are treated in their entirety by ray-tracing (so the matrix framework is not used). Both of these methods can be used in combination with TMM lookup tables to calculate realistic reflection, transmission and absorption probabilities. The function RT is used to create redistribution matrices, while the class rt_structure is used to define structures for ray-tracing. Note that for both of these methods, the default behaviour when using TMM lookup tables is to NOT recalculate the lookup tables if they already exist; currently, RayFlare does not detect whether you have e.g. changed the wavelength range or spacing, the interface layers, thicknesses, materials, or their coherence. To force recalculation, you can set the overwrite parameter to True in the RT function or the rt_structure class. Note that if you keep the interface layers the same but change the surface texture (e.g. opening angle of pyramids), you do not need to recalculate the lookup tables.

Individual function documentation:

rayflare.ray_tracing.rt_structure.calculate_interface_profiles(data_prof_layers, A_in_prof_layers, prof_layer_list_i, local_thetas_i, directions_i, z_list, offsets, lookuptable, local_pols_i, depth_spacing)
rayflare.ray_tracing.rt_structure.decide_end(abs_power, A_per_layer, ray_I)
rayflare.ray_tracing.rt_structure.make_lookuptable_rt_structure(textures, materials, incidence, transmission, options, save_location='default', overwrite=False)
rayflare.ray_tracing.rt_structure.make_rt_args(existing_rays, xs, ys, n_reps, phong_params, phong_options)

Make arguments for single_ray_stack with existing rays from analytical calculation.

rayflare.ray_tracing.rt_structure.make_tmm_args(arg_list)
rayflare.ray_tracing.rt_structure.parallel_inner(nks, alphas, r_a_0, surfaces, widths, cum_width, z_pos, depths, depth_indices, I_thresh, pol, initial_pol_vec, nx, ny, n_reps, xs, ys, randomize, initial_mat, initial_dir, periodic, d_theta, maximum_passes=0, tmm_args=None, existing_rays=None, n_jobs=-1)
rayflare.ray_tracing.rt_structure.ray_update_phong(ray, theta, phi, phong_options)
rayflare.ray_tracing.rt_structure.ray_update_phong_vec(ray_ds, pols, phong_options, n_rays)
rayflare.ray_tracing.rt_structure.rotate_vector(rot_mat, delta_theta, delta_phi)
rayflare.ray_tracing.rt_structure.rotation_matrix(theta, phi)
class rayflare.ray_tracing.rt_structure.rt_structure(textures, materials, widths, incidence, transmission, options=None, use_TMM=False, save_location='default', overwrite=False)

Set up structure for RT calculations.

Parameters:
  • textures – list of surface textures. Each entry in the list is another list of two RTSurface objects, describing what the surface looks like for front and rear incidence, respectively

  • materials – list of Solcore materials for each layer (excluding the incidence and transmission medium)

  • widths – list widths of the layers in m

  • incidence – incidence medium (Solcore material)

  • transmission – transmission medium (Solcore material)

  • options – dictionary/object with options for the calculation; only used if pre-computing lookup tables using TMM

  • use_TMM – if True, use TMM to pre-compute lookup tables for the structure. Surface layers most be specified in the relevant textures.

  • save_location – location to save the lookup tables; only used if pre-computing lookup tables using TMM

  • overwrite – if True, overwrite any existing lookup tables; only used if pre-computing lookup tables using TMM

calculate(options)

Calculates the reflected, absorbed and transmitted intensity of the structure for the wavelengths and angles defined.

Parameters:

options

options for the calculation. Relevant entries are:

  • wavelength: Wavelengths (in m) in which calculate the data. An array.

  • theta_in: Polar angle (in radians) of the incident light.

  • phi_in: azimuthal angle (in radians) of the incident light.

  • I_thresh: once the intensity reaches this fraction of the incident light, the light is considered to be absorbed.

  • maximum_passes: if 0 (default), keep following the ray until it is absorbed or escapes. Otherwise, assume the ray is Lambertian after this many traversals of the bulk.

  • pol: Polarisation of the light: ‘s’, ‘p’ or ‘u’, or a list/tuple of length 2 with the fraction of [‘s’, ‘p’] polarized light.

  • depth_spacing_bulk: depth spacing for absorption profile calculations in the bulk (m)

  • depth_spacing: depth spacing for absorption profile calculations in interface layers (m)

  • nx and ny: number of points to scan across the surface in the x and y directions (integers)

  • random_ray_position: True/False. instead of scanning across the surface, choose nx*ny points randomly

  • randomize_surface: True/False. Randomize the ray position in the x/y direction before each surface interaction

  • parallel: True/False. Whether to execute calculations in parallel

  • n_jobs: n_jobs argument for Parallel function of joblib. Controls how many threads are used.

  • x_limits: x limits (in same units as the size of the RTSurface) between which incident rays will be generated

  • y_limits: y limits (in same units as the size of the RTSurface) between which incident rays will be generated

Returns:

A State object (dictionary) with the following entries:

  • R: total reflectance (as a fraction) at each wavelength (array)

  • R0: reflectance at the first surface interaction only (n_passes = 0) (array)

  • T: total transmittance (as a fraction) at each wavelength (array)

  • A_per_layer: absorptance in each bulk (not interface!) layer at each wavelength. Dimensions are (wavelength, layer). (array)

  • A_per_interface: absorptance in the interface (if interface_layers were present). This is a list, with the length equal to the number of textures/surfaces in the structure. Each entry in the list is an array with dimensions (wavelength, n_interface_layers) where n_interface_layers is the number of layers in the corresponding interface.

  • profile: the absorption profile in the bulk layers. The spacing will be equal to options.depth_spacing_bulk. Units are m-1.

  • interface_profiles: the absorption profile in the interface layers, if requested. The spacing will be equal to options.depth_spacing. Units are nm-1 (note that this is not the same as the bulk profile!).

  • ray_data: this is a State object (dictionary) which contains information about the individual rays: their direction, polarization, initial and final position. Keys are:

    • xy_in: the initial x and y coordinates of each ray. List with two entries, the initial x positions and the initial y positions.

    • Is: the final intensity of each ray. Array with dimensions (wavelengths, n_rays)

    • thetas: the final polar angle of each ray (in radians). If less than pi/2, the ray is travelling upwards (reflection), if between pi/2 and pi it is transmitted. If the entry is NaN, the ray was absorbed in a bulk or interface layer. Array with dimensions (wavelengths, n_rays)

    • phis: the final polar angle of each ray (in radians). If the entry is NaN, the ray was absorbed in a bulk or interface layer. Array with dimensions (wavelengths, n_rays)

    • n_passes: number of passes through bulk materials. Array with dimensions (wavelengths, n_rays)

    • n_interactions: number of interactions. This counts TOTAL interactions with interface; a ray may interact with a single interface more than once per encounter. Array with dimensions (wavelengths, n_rays)

    • pol: the final polarization state of the ray. This is relative to the last surface it interacted with. Array with dimensions (wavelengths, n_rays, 2), with the final dimension containing the s-component and p-component (summing to 1) respectively.

    • pol_vectors: the final directions of the s and p polarization directions. Array with dimensions (wavelengths, n_rays, 2, 3).

    • intersection: the final intersection of the ray (xyz coordinates), before it was reflected, transmitted, or absorbed. Array with dimensions (wavelengths, n_rays, 3).

    To access, for example, the final polar angle (theta) distribution of the rays, you would use rt_result.ray_data.thetas or rt_result[‘ray_data’][‘thetas’].

calculate_profile(options)
rayflare.ray_tracing.rt_structure.single_ray_stack(nks, alphas, r_a, d, surfaces, tmm_kwargs_list, widths, abs_power, z_pos, depths, depth_indices, I_thresh, pol, pol_vec, d_theta, randomize=False, mat_i=0, direction=1, surf_index=0, periodic=1, maximum_passes=0, n_passes=0, n_interactions=0, I_in=1)
rayflare.ray_tracing.rt_structure.traverse(ray_I, width, theta, alpha, positions, I_thresh, direction)
rayflare.ray_tracing.rt_structure.update_ray_tracing_results(max_rays, n_rem, analytical_result, thetas, phis, Is, n_passes, n_interactions)
rayflare.ray_tracing.rt_matrix.RT(group, incidence, transmission, surf_name, options, structpath, Fr_or_TMM=0, front_or_rear='front', n_absorbing_layers=0, calc_profile=None, only_incidence_angle=False, widths=None, save=True, overwrite=False, analytical=False)

Calculates the reflection/transmission and absorption redistribution matrices for an interface using either a previously calculated TMM lookup table or the Fresnel equations.

Parameters:
  • group – an RTgroup object containing the surface textures

  • incidence – incidence medium

  • transmission – transmission medium

  • surf_name – name of the surface (to save matrices)

  • options – user options (State object)

  • structpath – file path where matrices will be stored or loaded from

  • Fr_or_TMM – whether to use the Fresnel equations (0) or a TMM lookup table (1)

  • front_or_rear – whether light is incident from the front or rear

  • n_absorbing_layers – for a structure with multiple interface layers, where a TMM lookuptable is used, the number of layers in the interface

  • calc_profile – whether to save the relevant information to calculate the depth-dependent absorption profile. List of layers where the profile should be calculated, or otherwise None

  • only_incidence_angle – if True, the ray-tracing will only be performed for the incidence theta and phi specified in the options.

  • widths – if using TMM, width of the surface layers (in nm)

  • save – whether to save redistribution matrices (True/False), default True

  • overwrite – whether to overwrite existing matrices (True/False), default False

Returns:

Number of returns depends on whether absorption profiles are being calculated; the first two items are always returned, the final one only if a profile is being calcualted.

  • allArrays: the R/T redistribution matrix at each wavelength, indexed as (wavelength, angle_bin_out, angle_bin_in)

  • absArrays: the absorption redistribution matrix (total absorption per layer), indexed as (wavelength, layer_out, angle_bin_in)

  • allres: xarray dataset storing the absorption profile data

rayflare.ray_tracing.rt_matrix.RT_wl(i1, wl, n_angles, nx, ny, widths, thetas_in, phis_in, h, xs, ys, nks, surfaces, pol, d_theta, phi_sym, theta_intv, phi_intv, angle_vector, Fr_or_TMM, n_abs_layers, lookuptable, calc_profile, depth_spacing, side)
rayflare.ray_tracing.rt_matrix.make_profiles_wl(unique_thetas, n_a_in, side, widths, angle_distmat, lookuptable, pol, depth_spacing, prof_layers)
rayflare.ray_tracing.rt_matrix.single_ray_interface(x, y, nks, r_a_0, theta, phi, surfaces, pol, pol_vec, d_theta, wl, Fr_or_TMM, lookuptable)
class rayflare.ray_tracing.rt_common.RTSurface(Points, interface_layers=None, phong=False, analytical=False, **kwargs)

Class which is used to store information about the surface which is used for ray-tracing.

find_area()
refresh()
shift(z_shift)
class rayflare.ray_tracing.rt_common.Ray(intensity, direction, current_location, s_vector, p_vector, pol)

Class to store ray information for ray-tracing calculations.

rayflare.ray_tracing.rt_common.calc_R(n1, n2, theta, pol_comps)
rayflare.ray_tracing.rt_common.calc_intersection_properties(t, which_intersect, r_a, d, tri_N)
rayflare.ray_tracing.rt_common.calculate_tuv(d, tri_size, tri_crossP, r_a, tri_P_0s, tri_P_2s, tri_P_1s)
rayflare.ray_tracing.rt_common.check_intersect(r_a, d, tri_size, tri_crossP, tri_P_0s, tri_P_2s, tri_P_1s, tri_N)
rayflare.ray_tracing.rt_common.decide_RT_Fresnel(ray, n0, n1, theta, N, side, rnd, lookuptable=None, d_theta=None)
rayflare.ray_tracing.rt_common.decide_RT_TMM(ray, n0, n1, theta, N, side, rnd, lookuptable, d_theta)
rayflare.ray_tracing.rt_common.exit_side(r_a, d, p_0)
rayflare.ray_tracing.rt_common.get_RT_data(theta, d_theta, R_data, T_data, Alayer_data, pol)
rayflare.ray_tracing.rt_common.get_pol_component_direction(theta, d, N, current_s_vector, current_p_vector, ray_pol)
rayflare.ray_tracing.rt_common.make_pol_vectors(pol_string, theta, phi)
rayflare.ray_tracing.rt_common.norm(x)
rayflare.ray_tracing.rt_common.normalize(x)
rayflare.ray_tracing.rt_common.random() x in the interval [0, 1).
rayflare.ray_tracing.rt_common.single_cell_check(ray, ni, nj, tri, Lx, Ly, side, z_cov, d_theta, n_interactions=0, wl=None, Fr_or_TMM=0, lookuptable=None)
rayflare.ray_tracing.rt_common.single_interface_check(ray, ni, nj, tri, Lx, Ly, side, z_cov, d_theta, n_interactions=0, wl=None, Fr_or_TMM=0, lookuptable=None)
rayflare.ray_tracing.rt_common.update_ray_d_pol(ray, rnd, R, T, Rs, Rp, Ts, Tp, A_per_layer, n0, n1, N, side, ray_plane_s_direction, s_comp_sq)