Real-space visualization of a rough interfaces

To generate a real-space visualization of a rough interface, use function

RoughnessMap(n_pts_x, n_pts_y, Lx, Ly, sample, i_layer[, seed])

It generates a random rough surface, iteratively adjusted to reproduce the given spectrum and height statistics. Algorithm by Pérez-Ràfols & Almqvist, Tribology International 131, 591-604 (2019).

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env python3
"""
Generates random rough surface of the sample with the given
heights statistics and lateral roughness spectrum.
"""

import numpy as np
import bornagain as ba
from bornagain import nm, nm2, nm3
from matplotlib import gridspec
from bornagain.numpyutil import Arrayf64Converter as dac

def plot(h):
    rms = np.std(surface)

    fig = bp.plt.figure(figsize=(10, 6))
    gs = gridspec.GridSpec(3, 2)
    gs.update(left=0.1, right=0.48, wspace=0.15, hspace=0.5)

    # map
    fig.add_subplot(gs[:-1, :])
    bp.plt.imshow(h, extent = [0, Lx, 0, Ly], cmap='inferno', aspect='auto')
    bp.plt.colorbar()

    # psd
    fig.add_subplot(gs[-1, 0])
    factor = X_points*Y_points/np.sqrt(Lx*Ly)
    N = np.floor(X_points/2 + 1).astype(int)
    psd = abs(np.fft.rfft2(h)/factor)**2
    psd_points_x = np.array([psd[0][i] for i in range(1, N)])
    f_points_x = np.array([i/Lx for i in range(1, N)])
    bp.plt.plot(f_points_x, psd_points_x)
    bp.plt.yscale('log')
    bp.plt.xscale('log')
    bp.plt.title('PSD')
    bp.plt.xlabel('$\\nu, nm^{-1}$')

    # hist
    fig.add_subplot(gs[-1, 1])
    bp.plt.hist(h.flatten(), range=[-4*rms, 4*rms],
             bins=300, color='black')
    bp.plt.title('Height histogram')
    bp.plt.xlabel('h, nm')
    bp.plt.tick_params(left = False, labelleft = False)

    bp.plt.show()

def get_sample():
    """
    A sample with one layer on a substrate, with partially
    correlated roughnesses.
    """
    # defining materials
    vacuum = ba.RefractiveMaterial("ambience", 0, 0)
    material_layer = ba.RefractiveMaterial("layer", 5e-6, 0)
    material_substrate = ba.RefractiveMaterial("substrate", 15e-6, 0)

    # defining roughness
    height_distribution = ba.ErfTransient()
    max_spat_freq = 0.5*nm

    # for layer
    omega = 1*nm3
    a1 = 1
    a2 = 10*nm
    a3 = 100*nm2
    a4 = 1000*nm3
    autocorr_layer = ba.LinearGrowthModel(omega, a1, a2, a3, a4, max_spat_freq)
    roughness_layer = ba.Roughness(autocorr_layer, height_distribution)

    # for substrate
    sigma = 0.9*nm
    alpha = 0.5
    xi = 35*nm
    autocorr_sub = ba.SelfAffineFractalModel(sigma, alpha, xi, max_spat_freq)
    roughness_sub = ba.Roughness(autocorr_sub, height_distribution)

    # defining layers
    l_ambience = ba.Layer(vacuum)
    l_layer = ba.Layer(material_layer, 25*nm, roughness_layer)
    l_substrate = ba.Layer(material_substrate, roughness_sub)

    # adding layers
    my_sample = ba.Sample()
    my_sample.addLayer(l_ambience)
    my_sample.addLayer(l_layer)
    my_sample.addLayer(l_substrate)

    return my_sample

if __name__ == '__main__':

    # sample size
    Lx = 1000*nm
    Ly = 1000*nm
    X_points = 512
    Y_points = 512

    sample = get_sample()
    layer_index = 1 # top interface
    seed = -1 # seed < 0 ==> random every time

    # generate roughness map
    roughness_map = ba.RoughnessMap(X_points, Y_points, Lx, Ly,
                                    sample, layer_index, seed)
    surface = dac.npArray(roughness_map.generate())
    print("rms = {:.3}".format(np.std(surface)),"nm")

    plot(surface)
    bp.plt.show()
auto/Examples/varia/RoughSurface.py