Skip to content

Scattering Models

The scatteringmodel module provides tools to calculate scattering amplitudes and form factors of multicomponent systems consisting of spherical particles.

Overview

Particles and Layers

Particles are represented by Particle objects composed of layers, each represented by a specific scattering length density profile. These layers can have different scattering properties, which are defined by the LayerProfile interface. The module includes several predefined layer profiles:

ParticleBuilder

The ParticleBuilder class is a utility to help construct particles layer by layer. Once the desired layers are added, a Particle instance can be created.

ScatteringModel

The ScatteringModel class calculates scattering properties for a list of particles. It can compute various properties such as scattering amplitudes, forward scattering amplitudes, and form factors.

Convenience Classes

There are several convenience classes provided to quickly create models for common scenarios from a given particle mixture:

  • SimpleSphere: For a mixture of homogeneously scattering spheres.
  • SimpleCoreShell: For a mixture of core-shell particles with a common core-to-shell ratio.
  • SimpleGradient: For a mixture of particles displaying a linear gradient of the scattering length density.

Example Usage

Using ParticleBuilder to Construct Particles

The ParticleBuilder class is used to construct particles by adding layers. Here’s an example of how to use it:

from mixscatter.scatteringmodel import (
    ParticleBuilder, ConstantProfile, LinearProfile
)

# Create a ParticleBuilder instance
builder = ParticleBuilder()

# Add a layer to the builder
builder.add_layer(ConstantProfile(0, 10, 1.0))

# Add another layer to the builder
builder.add_layer(LinearProfile(10, 20, 1.0, 0.0))

# Get the constructed particle
particle = builder.get_particle()

You can do the construction in a single command by chaining the operations like this:

builder = ParticleBuilder()
particle = (
            builder
            .add_layer(ConstantProfile(0, 10, 1.0))
            .add_layer(LinearProfile(10, 20, 1.0, 0.0))
            .get_particle()
           )

Accessing Single-Particle Properties

The Particle class provides methods for displaying the scattering length density profile and for calculating the scattering amplitude and the form factor of a single constructed particle:

profile = particle.get_profile(distance)

amplitude = particle.calculate_amplitude(wavevector)

forward_amplitude = particle.calculate_forward_amplitude()

form_factor = particle.calculate_form_factor(wavevector)

square_radius_of_gyration = particle.calculate_square_radius_of_gyration()

Using ScatteringModel

The ScatteringModel class calculates the scattering properties from a list of particles and a matching Mixture instance. Here’s an example of how to use it:

import numpy as np
from mixscatter.scatteringmodel import (
    ScatteringModel, ParticleBuilder, ConstantProfile
)
from mixscatter.mixture import Mixture

mixture = Mixture(radius=[1.0, 2.0], number_fraction=[0.5, 0.5])

# Create particles using ParticleBuilder
builder = ParticleBuilder()
# pop_particle() obtains the constructed particle and then resets the builder
particles = [
    builder.add_layer(ConstantProfile(0, radius, 1.0)).pop_particle()
    for radius in mixture.radius
    ]

# Create a ScatteringModel instance
wavevector = np.linspace(0.01, 1.0, 100)
model = ScatteringModel(wavevector, mixture, particles)

# Calculate the average form factor
form_factor = model.average_form_factor

A ScatteringModel can contain almost any conceivable combination of particles with totally different optical properties. This flexibility makes the tool particularly powerful.

Convenience Classes

The module includes several convenience classes to quickly create models for common particle types:

SimpleSphere

from mixscatter.scatteringmodel import SimpleSphere

# Create a simple sphere model
model = SimpleSphere(wavevector, mixture, contrast=1.0)
form_factor = model.average_form_factor

SimpleCoreShell

from mixscatter.scatteringmodel import SimpleCoreShell

# Create a core-shell model
model = SimpleCoreShell(
    wavevector,
    mixture,
    core_to_total_ratio=0.5,
    core_contrast=1.0,
    shell_contrast=0.5
    )
form_factor = model.average_form_factor

SimpleGradient

from mixscatter.scatteringmodel import SimpleGradient

# Create a gradient profile model
model = SimpleGradient(
    wavevector, mixture, center_contrast=1.0, boundary_contrast=0.5
    )
form_factor = model.average_form_factor

Implementing Your Own Model

To implement your own layer profile or scattering model from scratch, you can extend the LayerProfile and the ScatteringModel class. Here’s a basic example:

from mixscatter.scatteringmodel import (
    ScatteringModel, ParticleBuilder, LayerProfile
    )
import numpy as np

class CustomProfile(LayerProfile):
    def __init__(self, radius_inner, radius_outer, custom_param):
        self.radius_inner = radius_inner
        self.radius_outer = radius_outer
        self.custom_param = custom_param

    def calculate_amplitude(self, wavevector):
        wavevector = np.asarray(wavevector)
        # Custom amplitude calculation logic
        amplitude = ...  # Replace with actual calculation
        return amplitude

    def calculate_forward_amplitude(self):
        # Custom forward amplitude calculation logic
        forward_amplitude = ...  # Replace with actual calculation
        return forward_amplitude

    def get_profile(self, distance):
        distance = np.asarray(distance)
        # Custom profile calculation logic
        profile = ... # Replace with actual calculation
        return profile

class CustomModel(ScatteringModel):
    def __init__(self, wavevector, mixture, custom_param):
        particles = []
        particle_builder = ParticleBuilder()
        for radius in mixture.radius:
            particle = (
            particle_builder
            .add_layer(CustomProfile(0, radius, custom_param))
            # Add as many layers as you want
            .pop_particle()
            )
            particles.append(particle)
        super().__init__(wavevector, mixture, particles)

# Using the custom model
custom_param = 1.0
model = CustomModel(wavevector, mixture, custom_param)
form_factor = model.average_form_factor