Disordered 3D particle assemblies

Class Dilute3D models random assemblies of particles dispersed in the bulk of a layer. It can be used for thin films as long as the film thickness is greater than the particle diameter.

Possible applications are

  • nanoparticle-filled polymer films,
  • colloidal suspensions, and
  • any other system where particles (or holes) are dispersed in a matrix.

Creating a 3D assembly

To fill a layer with randomly distributed particles:

layer = ba.Layer(matrix_material, thickness)
layer.fill3D(ba.Dilute3D(density, particle))

If the layer contains an incoherent mixture of the disordered assembly and something else, use add3D with a coverage parameter:

layer = ba.Layer(matrix_material, thickness)
disordered = ba.Dilute3D(density, particle)
layer.add3D(coverage, disordered)

Parameters:

  • density: Volume number density in nm⁻³ (particles per cubic nanometer)
  • particle: The particle to distribute throughout the layer
  • coverage (second form only): surface coverage, between 0 and 1

Requirements

3D assemblies require material averaging to be enabled (the default). The layer thickness must be finite and larger than the particle size.

Examples

Dilute film

Spherical nanoparticles dispersed in a substrate layer:

Scattering from dilute film

 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
#!/usr/bin/env python3
"""
Dilute film of small spheres
"""
import bornagain as ba
from bornagain import ba_plot as bp, deg, nm, nm3


def get_sample():
    # Materials
    material_particle = ba.RefractiveMaterial("Particle", 6e-05, 2e-08)
    material_substrate = ba.RefractiveMaterial("Substrate", 6e-06, 2e-08)
    vacuum = ba.Vacuum()

    # Particles
    ff = ba.Sphere(2*nm)
    particle = ba.Particle(material_particle, ff, ba.AlignAt_Bottom)

    # Layers
    layer_1 = ba.Layer(vacuum)
    layer_2 = ba.Layer(material_substrate, 30*nm)
    layer_3 = ba.Layer(material_substrate)
    layer_2.fill3D(ba.Dilute3D(.0005/nm3, particle))

    # Sample
    sample = ba.Sample()
    sample.addLayer(layer_1)
    sample.addLayer(layer_2)
    sample.addLayer(layer_3)

    return sample


def get_simulation(sample):
    beam = ba.Beam(1e9, 0.1*nm, 0.2*deg)
    n = 100
    detector = ba.SphericalDetector(n, -1*deg, 1*deg, n, 0., 2*deg)
    simulation = ba.ScatteringSimulation(beam, sample, detector)
    return simulation


if __name__ == '__main__':
    sample = get_sample()
    simulation = get_simulation(sample)
    result = simulation.simulate()
    bp.plot_datafield(result, unit_aspect=1)
    bp.plt.show()
auto/Examples/scatter2d/DiluteFilm.py

Film vs monolayer

Comparison between a 3D film (fill3D) and a 2D monolayer (deposit2D). As film thickness increases, the scattering pattern evolves from the monolayer limit:

Film thickness dependence

scatter2d/FilmVsMonolayer.py
 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
#!/usr/bin/env python3
"""
Dilute film of small spheres
"""
import bornagain as ba
from bornagain import ba_plot as bp, deg, nm, nm2, nm3

particle_radius = 4*nm
particle_height = 2*particle_radius
area_density = .016/nm2


def get_sample(thickness):
    # Materials
    material_particle = ba.RefractiveMaterial("Particle", 1.5e-05, 2e-08)
    material_substrate = ba.RefractiveMaterial("Substrate", 1e-06, 2e-08)
    vacuum = ba.Vacuum()

    # Particles
    ff = ba.Sphere(particle_radius)
    particle = ba.Particle(material_particle, ff, ba.AlignAt_Bottom)

    # Layers
    layer_1 = ba.Layer(vacuum)
    layer_3 = ba.Layer(material_substrate)
    if thickness > 0:
        layer_2 = ba.Layer(material_substrate, thickness)
        volume_density = area_density/thickness
        layer_2.fill3D(ba.Dilute3D(volume_density, particle))
    else:
        layer_1.deposit2D(ba.Dilute2D(area_density, particle))

    # Sample
    sample = ba.Sample()
    sample.addLayer(layer_1)
    if thickness > 0:
        sample.addLayer(layer_2)
    sample.addLayer(layer_3)

    return sample


def get_simulation(sample):
    beam = ba.Beam(1e9, 0.1*nm, 0.2*deg)
    n = 100
    # Just compute a 1d cut at phi=0
    detector = ba.SphericalDetector(1, -1*deg, 1*deg, n, 0., 2*deg)
    simulation = ba.ScatteringSimulation(beam, sample, detector)
    return simulation


if __name__ == '__main__':
    thicknesses = [
        0*nm, particle_height, 2*particle_height, 4*particle_height,
        8*particle_height
    ]
    labels = ["Monolayer"]
    labels.extend(f'{t/nm:.0f} nm' for t in thicknesses[1:])
    samples = [ get_sample(t) for t in thicknesses ]
    results = [ get_simulation(sample).simulate() for sample in samples ]
    for r in results:
        bp.plot_datafield(r, intensity_max=1e6, intensity_min=1e-4)
    bp.plt.legend(labels)
    bp.plt.show()
auto/Examples/scatter2d/FilmVsMonolayer.py