First steps
We here collect simple examples for using the package to demonstrate some of its functionality.
Basic PDE simulation
A simple simulation of a partial differential equation (PDE) can be run as follows.
"""
Simple PDE
==========
Demonstrates a minimal example involving the diffusion equation
"""
from pde import DiffusionPDE, ScalarField, UnitGrid
import emulsim
# set up state
field = ScalarField.random_uniform(UnitGrid([32, 32], periodic=True))
element = emulsim.ScalarFieldElement.from_field(field)
state = emulsim.State({"field": element})
# set up simulation
simulation = emulsim.Simulation(state)
eq = DiffusionPDE(diffusivity=0.1)
simulation.add_actor("field", emulsim.ScalarPDEActor(eq))
# run simulation
result = simulation.run(t_range=10, dt=0.1)
result.plot()
General, each simulation is split in three parts: First, the simulation elements
are combined to a simulation state. This defines what can be evolved in time.
Second, the actors are added to a simulation. This determines how the elements
change in time. Finally, the simulation is actually run and results are collected.
Here, result is a State class like state, but with
updated data.
Droplets simulation
The package becomes useful, when multiple elements interact. A simple example are droplets exchange material via a background phase:
"""
Simple droplet dynamics
=======================
Minimal examples of passive droplets interacting in a common background.
"""
from droplets import SphericalDroplet
from pde import ScalarField, UnitGrid
import emulsim
# set up state
grid = UnitGrid([32, 32], periodic=True)
background = emulsim.ScalarFieldElement.from_field(ScalarField(grid, 0.1))
droplet_data = [SphericalDroplet(grid.get_random_point(), 0.5) for _ in range(10)]
droplets = emulsim.SphericalDropletsElement.from_droplets(droplet_data)
state = emulsim.State({"background": background, "droplets": droplets})
# set up simulation
simulation = emulsim.Simulation(state)
simulation.add_actor("background", emulsim.DiffusionActor())
simulation.add_actor(("droplets", "background"), emulsim.SphericalDropletActor())
# run simulation
result = simulation.run(t_range=10)
result.plot()
Custom actor
One strength of the package is that actors can be simply defined, as shown below
"""
Custom Brownian motion class
============================
Demonstrates the custom implementation of Brownian motion.
"""
import numpy as np
import emulsim
class BrownianParticlesActor(emulsim.ActorBase):
diffusivity = 1
def evolve(self, elements, t, dt):
"""Evolve the particles in time."""
(particles,) = elements
scale = np.sqrt(dt) * self.diffusivity
size = particles.positions.shape
particles.positions[...] += scale * np.random.normal(size=size)
# set up state
particle_data = np.random.uniform(0, 100, size=(10, 2))
particles = emulsim.PointsElement(particle_data)
state = emulsim.State({"particles": particles})
# set up simulation
simulation = emulsim.Simulation(state)
simulation.add_actor("particles", BrownianParticlesActor())
# run simulation
result = simulation.run(t_range=10)
result.plot()
Here, we define an actor that moves points like Brownian particle, i.e., they simply diffuse around and do not interact with each other.