Monte-Carlo packings#
The Monte-Carlo namespace implements random sequential adsorption (RSA) of non-overlapping spheres. Its workflow is intentionally explicit: define the box, define how radii are drawn, choose stopping conditions, then run.
Configure the domain and sampler#
PackingDomain takes the three box widths and a periodic flag. Radius
samplers accept dimensional radii and include constant, uniform, normal,
log-normal, and discrete distributions.
from PackLab import monte_carlo, samplers
from PackLab.units import ureg
domain = monte_carlo.PackingDomain(
length_x=10 * ureg.micrometer,
length_y=10 * ureg.micrometer,
length_z=10 * ureg.micrometer,
use_periodic_boundaries=True,
)
radii = samplers.LogNormalRadiusSampler(
median_radius=150 * ureg.nanometer,
geometric_standard_deviation=1.15,
maximum_radius_clip=250 * ureg.nanometer,
)
Run RSA#
maximum_attempts controls how long RSA continues after unsuccessful
proposals. target_packing_fraction is optional and stops the simulation as
soon as the requested fraction is reached.
options = monte_carlo.RSAOptions()
options.maximum_attempts = 100_000
options.target_packing_fraction = 0.15
result = monte_carlo.RSASimulator(domain, radii, options).run()
Inspecting results#
PackingResult exposes the accepted configuration and helper methods for
visualisation and statistics. For example:
print(result)
figure = result.plot_slice_2d()
For a radial pair-correlation estimate, build a PackingStatistics instance
from the result and choose bins appropriate to the box dimensions. Periodic
domains are generally the right choice for bulk correlation estimates because
they avoid treating the box faces as physical boundaries.
Equilibrating a configuration with Metropolis moves#
RSA is an irreversible deposition process. To sample a fixed-volume
equilibrium hard-sphere system, use its valid configuration only as the
initial state of MetropolisSimulator. The sampler proposes symmetric,
single-particle displacements and accepts a proposal when it creates no hard
sphere overlap. It preserves the number of particles, radii, and class labels.
metropolis_options = monte_carlo.MetropolisOptions()
metropolis_options.random_seed = 42
metropolis_options.number_of_sweeps = 1_000
metropolis_options.maximum_displacement = 50 * ureg.nanometer
simulator = monte_carlo.MetropolisSimulator(
domain,
result.sphere_configuration,
metropolis_options,
)
equilibrated_result = simulator.run()
print(simulator.statistics.acceptance_rate)
The displacement controls the acceptance rate and should be tuned for the density and particle sizes. A finite number of sweeps alone does not establish equilibration: assess stationarity and collect independent samples for the observable of interest.