Effect of front pyramid texture and/or rear grating on absorption in Si

This example is based on Figures 6, 7 and 8 from this paper. This compares three different structures, all based on a 200 micron thick slab of silicon with different surface textures:

  1. Planar front surface (TMM), crossed grating at rear (RCWA)

  2. Inverted pyramids on the front surface (RT_Fresnel), planar rear surface (TMM)

  3. Inverted pyramids on the front surface (RT_Fresnel), crossed grating at rear (RCWA)

The methods which will be used to calculate the redistribution matrices in each case are given in brackets. If case 1 and 2 are calculated first, then case 3 does not require the calculations of any additional matrices, since it will use the rear matrix from (1) and the front matrix from (2).

First, importing relevant packages:

[1]:
import numpy as np
import os
# solcore imports
from solcore.structure import Layer
from solcore import material
from solcore import si

from rayflare.structure import Interface, BulkLayer, Structure
from rayflare.matrix_formalism import process_structure, calculate_RAT, get_savepath
from rayflare.transfer_matrix_method import tmm_structure
from rayflare.angles import theta_summary, make_angle_vector
from rayflare.textures import regular_pyramids
from rayflare.options import default_options

from solcore.material_system import create_new_material
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns
from sparse import load_npz

To make sure we are using the same optical constants for Si, load the same Si n/k data used in the paper linked above:

[2]:
create_new_material('Si_OPTOS', 'Si_OPTOS_n.txt', 'Si_OPTOS_k.txt')

You only need to do this one time, then the material will be stored in Solcore’s material database.

Setting options (taking the default options for everything not specified explicitly):

[3]:
angle_degrees_in = 8

wavelengths = np.linspace(900, 1200, 30)*1e-9

Si = material('Si_OPTOS')()
Air = material('Air')()

options = default_options()
options.wavelengths = wavelengths
options.theta_in = angle_degrees_in*np.pi/180
options.n_theta_bins = 100
options.c_azimuth = 0.25
options.n_rays = 25*25*1300
options.project_name = 'OPTOS_comparison'
options.orders = 60
options.pol = 'u'

Now, set up the grating basis vectors for the RCWA calculations and define the grating structure. These are squares, rotated by 45 degrees. The halfwidth is calculated based on the area fill factor of the etched pillars given in the paper.

[4]:
x = 1000

d_vectors = ((x, 0),(0,x))
area_fill_factor = 0.36
hw = np.sqrt(area_fill_factor)*500

back_materials = [Layer(si('120nm'), Si,
                        geometry=[{'type': 'rectangle', 'mat': Air,
                                   'center': (x/2, x/2),
                                   'halfwidths': (hw, hw), 'angle': 45}])]

Now we define the pyramid texture for the front surface in case (2) and (3) and make the four possible different surfaces: planar front and rear, front with pyramids, rear with grating. We specify the method to use to calculate the redistribution matrices in each case and create the bulk layer.

[5]:
surf = regular_pyramids(elevation_angle=55, upright=False)

front_surf_pyramids = Interface('RT_Fresnel', texture = surf, layers=[],
                                name = 'inv_pyramids_front_' + str(options['n_rays']))

front_surf_planar = Interface('TMM', layers=[], name='planar_front')

back_surf_grating = Interface('RCWA', layers=back_materials, name='crossed_grating_back',
                              d_vectors=d_vectors, rcwa_orders=60)

back_surf_planar = Interface('TMM', layers=[], name = 'planar_back')

bulk_Si = BulkLayer(201.8e-6, Si, name = 'Si_bulk')

Now we create the different structures and ‘process’ them (this will calculate the relevant matrices if necessary, or do nothing if it finds the matrices have previously been calculated and the files already exist). We don’t need to process the final structure because it will use matrices calculated for SC_fig6 and SC_fig7.

[6]:
SC_fig6 = Structure([front_surf_planar, bulk_Si, back_surf_grating],
                    incidence=Air, transmission=Air)
SC_fig7 = Structure([front_surf_pyramids, bulk_Si, back_surf_planar],
                    incidence=Air, transmission=Air)
SC_fig8 = Structure([front_surf_pyramids, bulk_Si, back_surf_grating],
                    incidence=Air, transmission=Air)

process_structure(SC_fig6, options)
process_structure(SC_fig7, options)
Making matrix for planar surface using TMM for element 0 in structure
Existing angular redistribution matrices found
Existing angular redistribution matrices found
RCWA calculation for element 2 in structure
Existing angular redistribution matrices found
Ray tracing with Fresnel equations for element 0 in structure
Existing angular redistribution matrices found
Existing angular redistribution matrices found
Making matrix for planar surface using TMM for element 2 in structure
Existing angular redistribution matrices found

Then we ask RayFlare to calculate the reflection, transmission and absorption through matrix multiplication, and get the required result out (absorption in the bulk) for each cell. We also load the results from the reference paper to compare them to the ones calculated with RayFlare.

[7]:
results_fig6= calculate_RAT(SC_fig6, options)
results_fig7 = calculate_RAT(SC_fig7, options)
results_fig8 = calculate_RAT(SC_fig8, options)

RAT_fig6 = results_fig6[0]
RAT_fig7 = results_fig7[0]
RAT_fig8 = results_fig8[0]

sim_fig6 = np.loadtxt('optos_fig6_sim.csv', delimiter=',')
sim_fig7 = np.loadtxt('optos_fig7_sim.csv', delimiter=',')
sim_fig8 = np.loadtxt('optos_fig8_sim.csv', delimiter=',')
After iteration 1 : maximum power fraction remaining = 0.3390767988491941
After iteration 2 : maximum power fraction remaining = 0.30068548096753706
After iteration 3 : maximum power fraction remaining = 0.2784848464103883
After iteration 4 : maximum power fraction remaining = 0.2597236607054195
After iteration 5 : maximum power fraction remaining = 0.24283861488498668
After iteration 6 : maximum power fraction remaining = 0.2274463776243316
After iteration 7 : maximum power fraction remaining = 0.21338566868684725
After iteration 8 : maximum power fraction remaining = 0.20053647198716856
After iteration 9 : maximum power fraction remaining = 0.1887906494269236
After iteration 10 : maximum power fraction remaining = 0.1780472110410226
After iteration 11 : maximum power fraction remaining = 0.16821201317116935
After iteration 12 : maximum power fraction remaining = 0.15919808370811278
After iteration 13 : maximum power fraction remaining = 0.1509257772675836
After iteration 14 : maximum power fraction remaining = 0.14332265118392196
After iteration 15 : maximum power fraction remaining = 0.1363231317935652
After iteration 16 : maximum power fraction remaining = 0.1298680613994831
After iteration 17 : maximum power fraction remaining = 0.12390419393397609
After iteration 18 : maximum power fraction remaining = 0.11838368175975715
After iteration 19 : maximum power fraction remaining = 0.11326357753101973
After iteration 20 : maximum power fraction remaining = 0.10850536353565393
After iteration 21 : maximum power fraction remaining = 0.10407451425200458
After iteration 22 : maximum power fraction remaining = 0.09994009407210737
After iteration 23 : maximum power fraction remaining = 0.09607439003385103
After iteration 24 : maximum power fraction remaining = 0.09245257824633178
After iteration 25 : maximum power fraction remaining = 0.08905242208069361
After iteration 26 : maximum power fraction remaining = 0.08585399990612694
After iteration 27 : maximum power fraction remaining = 0.08283946004811377
After iteration 28 : maximum power fraction remaining = 0.07999280065746482
After iteration 29 : maximum power fraction remaining = 0.077299672257999
After iteration 30 : maximum power fraction remaining = 0.07474720085895666
After iteration 31 : maximum power fraction remaining = 0.07232382965699143
After iteration 32 : maximum power fraction remaining = 0.07001917750001677
After iteration 33 : maximum power fraction remaining = 0.06782391243374476
After iteration 34 : maximum power fraction remaining = 0.06572963879669615
After iteration 35 : maximum power fraction remaining = 0.06372879646791475
After iteration 36 : maximum power fraction remaining = 0.06181457100194055
After iteration 37 : maximum power fraction remaining = 0.05998081350696946
After iteration 38 : maximum power fraction remaining = 0.058221969234271205
After iteration 39 : maximum power fraction remaining = 0.05653301394991912
After iteration 40 : maximum power fraction remaining = 0.05490939725399645
After iteration 41 : maximum power fraction remaining = 0.05334699209811126
After iteration 42 : maximum power fraction remaining = 0.05184204982978082
After iteration 43 : maximum power fraction remaining = 0.050391160162578955
After iteration 44 : maximum power fraction remaining = 0.048991215534435105
After iteration 45 : maximum power fraction remaining = 0.047639379373680305
After iteration 46 : maximum power fraction remaining = 0.046333057843886846
After iteration 47 : maximum power fraction remaining = 0.045102221747937425
After iteration 48 : maximum power fraction remaining = 0.04401110332606035
After iteration 49 : maximum power fraction remaining = 0.04295481662412294
After iteration 50 : maximum power fraction remaining = 0.041931515290021995
After iteration 51 : maximum power fraction remaining = 0.040939506770980946
After iteration 52 : maximum power fraction remaining = 0.03997723653384535
After iteration 53 : maximum power fraction remaining = 0.039043274018236
After iteration 54 : maximum power fraction remaining = 0.03813630012964539
After iteration 55 : maximum power fraction remaining = 0.03725509610076167
After iteration 56 : maximum power fraction remaining = 0.03639853356825749
After iteration 57 : maximum power fraction remaining = 0.035565565729209686
After iteration 58 : maximum power fraction remaining = 0.03475521945642275
After iteration 59 : maximum power fraction remaining = 0.03396658826539812
After iteration 60 : maximum power fraction remaining = 0.0331988260376919
After iteration 61 : maximum power fraction remaining = 0.03245114141608763
After iteration 62 : maximum power fraction remaining = 0.03172279279651709
After iteration 63 : maximum power fraction remaining = 0.03101308385011544
After iteration 64 : maximum power fraction remaining = 0.0303213595163102
After iteration 65 : maximum power fraction remaining = 0.02964700241451768
After iteration 66 : maximum power fraction remaining = 0.028989429627947018
After iteration 67 : maximum power fraction remaining = 0.028348089818272432
After iteration 68 : maximum power fraction remaining = 0.02772246063460141
After iteration 69 : maximum power fraction remaining = 0.02711204638430717
After iteration 70 : maximum power fraction remaining = 0.02651637593696439
After iteration 71 : maximum power fraction remaining = 0.025935000835882214
After iteration 72 : maximum power fraction remaining = 0.02536749359461314
After iteration 73 : maximum power fraction remaining = 0.024813446158372415
After iteration 74 : maximum power fraction remaining = 0.024272468512567952
After iteration 75 : maximum power fraction remaining = 0.023744187422646758
After iteration 76 : maximum power fraction remaining = 0.023228245291241588
After iteration 77 : maximum power fraction remaining = 0.02272429912017558
After iteration 78 : maximum power fraction remaining = 0.022232019566277114
After iteration 79 : maximum power fraction remaining = 0.021751090081191825
After iteration 80 : maximum power fraction remaining = 0.02128120612647292
After iteration 81 : maximum power fraction remaining = 0.02082207445619906
After iteration 82 : maximum power fraction remaining = 0.020373412460227884
After iteration 83 : maximum power fraction remaining = 0.019934947561952864
After iteration 84 : maximum power fraction remaining = 0.019506416665105077
After iteration 85 : maximum power fraction remaining = 0.01908756564473814
After iteration 86 : maximum power fraction remaining = 0.018678148878063402
After iteration 87 : maximum power fraction remaining = 0.01827792881127171
After iteration 88 : maximum power fraction remaining = 0.0178866755588935
After iteration 89 : maximum power fraction remaining = 0.01750416653261793
After iteration 90 : maximum power fraction remaining = 0.017130186096819097
After iteration 91 : maximum power fraction remaining = 0.01676452524832753
After iteration 92 : maximum power fraction remaining = 0.016406981318243294
After iteration 93 : maximum power fraction remaining = 0.016057357693815964
After iteration 94 : maximum power fraction remaining = 0.015715463558620336
After iteration 95 : maximum power fraction remaining = 0.015381113649437868
After iteration 96 : maximum power fraction remaining = 0.015054128028414718
After iteration 97 : maximum power fraction remaining = 0.014734331869210814
After iteration 98 : maximum power fraction remaining = 0.0144215552559819
After iteration 99 : maximum power fraction remaining = 0.014115632994150487
After iteration 100 : maximum power fraction remaining = 0.013816404432023116
After iteration 101 : maximum power fraction remaining = 0.013523713292401845
After iteration 102 : maximum power fraction remaining = 0.013237407513419104
After iteration 103 : maximum power fraction remaining = 0.012957339097897183
After iteration 104 : maximum power fraction remaining = 0.012683363970598539
After iteration 105 : maximum power fraction remaining = 0.01241534184279108
After iteration 106 : maximum power fraction remaining = 0.012153136083604655
After iteration 107 : maximum power fraction remaining = 0.011896613597701531
After iteration 108 : maximum power fraction remaining = 0.011645644708825688
After iteration 109 : maximum power fraction remaining = 0.011400103048833472
After iteration 110 : maximum power fraction remaining = 0.011159865451841914
After iteration 111 : maximum power fraction remaining = 0.010924811853161884
After iteration 112 : maximum power fraction remaining = 0.010694825192710599
After iteration 113 : maximum power fraction remaining = 0.010469791322623089
After iteration 114 : maximum power fraction remaining = 0.01024959891880466
After iteration 115 : maximum power fraction remaining = 0.010034139396186968
After iteration 116 : maximum power fraction remaining = 0.009823306827468582
After iteration 1 : maximum power fraction remaining = 0.6370516146387727
After iteration 2 : maximum power fraction remaining = 0.5271112820105328
After iteration 3 : maximum power fraction remaining = 0.4716921842696088
After iteration 4 : maximum power fraction remaining = 0.4127224542420158
After iteration 5 : maximum power fraction remaining = 0.3768591810603511
After iteration 6 : maximum power fraction remaining = 0.33419337003668925
After iteration 7 : maximum power fraction remaining = 0.3052216231242835
After iteration 8 : maximum power fraction remaining = 0.2729688578026014
After iteration 9 : maximum power fraction remaining = 0.24887960350980076
After iteration 10 : maximum power fraction remaining = 0.22371589535864844
After iteration 11 : maximum power fraction remaining = 0.20366225493246165
After iteration 12 : maximum power fraction remaining = 0.18366828158689408
After iteration 13 : maximum power fraction remaining = 0.16702215929995584
After iteration 14 : maximum power fraction remaining = 0.1510896120972171
After iteration 15 : maximum power fraction remaining = 0.137511439618598
After iteration 16 : maximum power fraction remaining = 0.12465164094509787
After iteration 17 : maximum power fraction remaining = 0.11339041277465066
After iteration 18 : maximum power fraction remaining = 0.10287334858270852
After iteration 19 : maximum power fraction remaining = 0.09354694511567849
After iteration 20 : maximum power fraction remaining = 0.08491739687705924
After iteration 21 : maximum power fraction remaining = 0.07720087755069409
After iteration 22 : maximum power fraction remaining = 0.07010470237060026
After iteration 23 : maximum power fraction remaining = 0.06372435535057148
After iteration 24 : maximum power fraction remaining = 0.0578807427619015
After iteration 25 : maximum power fraction remaining = 0.05260751601837906
After iteration 26 : maximum power fraction remaining = 0.04779083738006902
After iteration 27 : maximum power fraction remaining = 0.0434339000392318
After iteration 28 : maximum power fraction remaining = 0.03946121909803438
After iteration 29 : maximum power fraction remaining = 0.035862055919694436
After iteration 30 : maximum power fraction remaining = 0.03258414226110354
After iteration 31 : maximum power fraction remaining = 0.02961134281049521
After iteration 32 : maximum power fraction remaining = 0.026905961775991784
After iteration 33 : maximum power fraction remaining = 0.024450729966240727
After iteration 34 : maximum power fraction remaining = 0.02221748479333262
After iteration 35 : maximum power fraction remaining = 0.020189826442693418
After iteration 36 : maximum power fraction remaining = 0.01834610651452777
After iteration 37 : maximum power fraction remaining = 0.016671623439731227
After iteration 38 : maximum power fraction remaining = 0.015149371128563875
After iteration 39 : maximum power fraction remaining = 0.01376658206210366
After iteration 40 : maximum power fraction remaining = 0.012509684158263491
After iteration 41 : maximum power fraction remaining = 0.011367795056360144
After iteration 42 : maximum power fraction remaining = 0.010329962029774757
After iteration 43 : maximum power fraction remaining = 0.009387015366664989
After iteration 1 : maximum power fraction remaining = 0.8010305402542891
After iteration 2 : maximum power fraction remaining = 0.6912152237943677
After iteration 3 : maximum power fraction remaining = 0.5988256023436629
After iteration 4 : maximum power fraction remaining = 0.5180075060352245
After iteration 5 : maximum power fraction remaining = 0.4463565049529955
After iteration 6 : maximum power fraction remaining = 0.3840311705777717
After iteration 7 : maximum power fraction remaining = 0.33003854530303445
After iteration 8 : maximum power fraction remaining = 0.28346900980181144
After iteration 9 : maximum power fraction remaining = 0.24338163959974404
After iteration 10 : maximum power fraction remaining = 0.20892038696341841
After iteration 11 : maximum power fraction remaining = 0.17931693853832312
After iteration 12 : maximum power fraction remaining = 0.1538975394950654
After iteration 13 : maximum power fraction remaining = 0.13207619764237685
After iteration 14 : maximum power fraction remaining = 0.11334629994041201
After iteration 15 : maximum power fraction remaining = 0.09727120831311792
After iteration 16 : maximum power fraction remaining = 0.08347528399678891
After iteration 17 : maximum power fraction remaining = 0.0716357078966736
After iteration 18 : maximum power fraction remaining = 0.06147521913240223
After iteration 19 : maximum power fraction remaining = 0.052755770029974315
After iteration 20 : maximum power fraction remaining = 0.0452730207853331
After iteration 21 : maximum power fraction remaining = 0.038851587066273646
After iteration 22 : maximum power fraction remaining = 0.03334094695351067
After iteration 23 : maximum power fraction remaining = 0.028611921512315
After iteration 24 : maximum power fraction remaining = 0.024553650967075118
After iteration 25 : maximum power fraction remaining = 0.021070998056744547
After iteration 26 : maximum power fraction remaining = 0.018082318820155263
After iteration 27 : maximum power fraction remaining = 0.015517549146663855
After iteration 28 : maximum power fraction remaining = 0.013316562514188418
After iteration 29 : maximum power fraction remaining = 0.011427760559059025
After iteration 30 : maximum power fraction remaining = 0.009806863505205106

Finally, we use TMM to calculate the absorption in a structure with a planar front and planar rear, as a reference.

[8]:
struc = tmm_structure([Layer(si('200um'), Si)], incidence=Air, transmission=Air)
options.coherent = False
options.coherency_list = ['i']
RAT = tmm_structure.calculate(struc, options)

Plot everything together:

[9]:
palhf = sns.color_palette("hls", 4)

fig = plt.figure()
plt.plot(sim_fig6[:,0], sim_fig6[:,1], '--', color=palhf[0],
         label= 'OPTOS - rear grating (1)')
plt.plot(wavelengths*1e9, RAT_fig6['A_bulk'][0], '-o', color=palhf[0],
         label='RayFlare - rear grating (1)', fillstyle='none')
plt.plot(sim_fig7[:,0], sim_fig7[:,1], '--', color=palhf[1],
         label= 'OPTOS - front pyramids (2)')
plt.plot(wavelengths*1e9, RAT_fig7['A_bulk'][0], '-o', color=palhf[1],
         label= 'RayFlare - front pyramids (2)', fillstyle='none')
plt.plot(sim_fig8[:,0], sim_fig8[:,1], '--', color=palhf[2],
         label= 'OPTOS - grating + pyramids (3)')
plt.plot(wavelengths*1e9, RAT_fig8['A_bulk'][0], '-o', color=palhf[2],
         label= 'RayFlare - grating + pyramids (3)', fillstyle='none')
plt.plot(wavelengths*1e9, RAT['A_per_layer'][:,0], '-k', label='Planar')
plt.legend(loc='lower left')
plt.xlabel('Wavelength (nm)')
plt.ylabel('Absorption in Si')
plt.xlim([900, 1200])
plt.ylim([0, 1])
plt.show()
../_images/Examples_grating_pyramids_OPTOS_17_0.png

We can see good agreement between the reference values and our calculated values. The structure with rear grating also behaves identically to the planar TMM reference case at the short wavelengths where front surface reflection dominates the result, as expected. Clearly, the pyramids perform much better overall, giving a large boost in the absorption at long wavelengths and also reducing the reflection significantly at shorter wavelengths. Plotting reflection and transmission emphasises this:

[10]:
fig = plt.figure()
plt.plot(wavelengths*1e9, RAT_fig6['R'][0], '-o', color=palhf[0],
         label='RayFlare - rear grating (1)', fillstyle='none')
plt.plot(wavelengths*1e9, RAT_fig7['R'][0], '-o', color=palhf[1],
         label= 'RayFlare - front pyramids (2)', fillstyle='none')
plt.plot(wavelengths*1e9, RAT_fig8['R'][0], '-o', color=palhf[2],
         label= 'RayFlare - grating + pyramids (3)', fillstyle='none')

plt.plot(wavelengths*1e9, RAT_fig6['T'][0], '--o', color=palhf[0])
plt.plot(wavelengths*1e9, RAT_fig7['T'][0], '--o', color=palhf[1])
plt.plot(wavelengths*1e9, RAT_fig8['T'][0], '--o', color=palhf[2])

# these are just to create the legend:
plt.plot(-1, 0, 'k-o', label='R', fillstyle='none')
plt.plot(-1, 0, 'k--o', label='T')

plt.legend()
plt.xlabel('Wavelength (nm)')
plt.ylabel('Reflected/transmitted fraction')
plt.xlim([900, 1200])
plt.ylim([0, 0.6])
plt.show()
../_images/Examples_grating_pyramids_OPTOS_19_0.png

Plot the redistribution matrix for the rear grating (summed over azimuthal angles) at 1100 nm:

[11]:
theta_intv, phi_intv, angle_vector = make_angle_vector(options['n_theta_bins'],
                                                       options['phi_symmetry'],
                                                       options['c_azimuth'])


path = get_savepath('default', options.project_name)
sprs = load_npz(os.path.join(path, SC_fig6[2].name + 'frontRT.npz'))

wl_to_plot = 1100e-9

wl_index = np.argmin(np.abs(wavelengths-wl_to_plot))

full = sprs[wl_index].todense()

summat = theta_summary(full, angle_vector, options['n_theta_bins'], 'front')

summat_r = summat[:options['n_theta_bins'], :]

summat_r = summat_r.rename({r'$\theta_{in}$': r'$\sin(\theta_{in})$',
                            r'$\theta_{out}$': r'$\sin(\theta_{out})$'})

summat_r = summat_r.assign_coords({r'$\sin(\theta_{in})$':
                                       np.sin(summat_r.coords[r'$\sin(\theta_{in})$']).data,
                                    r'$\sin(\theta_{out})$':
                                        np.sin(summat_r.coords[r'$\sin(\theta_{out})$']).data})


palhf = sns.cubehelix_palette(256, start=.5, rot=-.9)
palhf.reverse()
seamap = mpl.colors.ListedColormap(palhf)

fig = plt.figure()
ax = plt.subplot(111)
ax = summat_r.plot.imshow(ax=ax, cmap=seamap, vmax=0.3)
plt.show()
../_images/Examples_grating_pyramids_OPTOS_21_0.png