QuickCompress

Struct QuickCompress 

Source
pub struct QuickCompress<C> { /* private fields */ }
Expand description

Quickly compress a microstate to a target volume.

QuickCompress allows you to quickly compress a microstate to a target volume. It does so by breaking detailed balance, so you should use it only during the initialization phase of your simulation where you prepare a microstate for later equilibration. It works best with the OverlapPenalty potential that allows sites to overlap a small amount and for trial moves to partially reduce that overlap.

As a algorithm, QuickCompress is more than just a trial move, it stores internal state to track its progress. Therefore, you should only use a given QuickCompress on one Microstate.

When not complete, apply takes the following steps:

  1. Check the total energy of the given Hamiltonian.
  2. If the total energy is less than or equal to zero and the microstate boundary’s volume does not match target_volume, compress (or expand) the boundary a small amount toward the target. Reject any trial move that increases the per-site energy of the system more than maximum_energy_per_site. Accept in all other cases.

When the target volume is reached and the total energy is less than or equal to 0, QuickCompress transitions to the complete state. When complete, is_complete returns true and apply returns immediately.

The generic type names are:

§Example

use hoomd_geometry::shape::Rectangle;
use hoomd_mc::QuickCompress;
use hoomd_microstate::boundary::Closed;

let quick_compress = QuickCompress::<Closed<Rectangle>>::with_target_volume(
    1000.0.try_into()?,
);

Implementations§

Source§

impl<C> QuickCompress<C>

Source

pub fn with_target_volume(target_volume: PositiveReal) -> Self

Construct a new QuickCompress with the given target volume.

The returned QuickCompress will compress (or expand) the microstate until the boundary reaches target_volume.

These defaults are suitable for use with the default OverlapPenalty parameters applied to typical hard-particle systems.

§Example
use hoomd_geometry::shape::Rectangle;
use hoomd_mc::QuickCompress;
use hoomd_microstate::boundary::Closed;

let quick_compress = QuickCompress::<Closed<Rectangle>>::with_target_volume(
    1000.0.try_into()?,
);
Source

pub fn is_complete(&self) -> bool

Check if the compression has completed.

is_complete will return true when the microstate has reached the target volume and the total energy of the system was less than or equal to zero during a call to apply. After that, is_complete will continue to return true even when the system energy changes.

§Example
use hoomd_geometry::shape::Rectangle;
use hoomd_mc::QuickCompress;
use hoomd_microstate::boundary::Closed;

let quick_compress = QuickCompress::<Closed<Rectangle>>::with_target_volume(
    1000.0.try_into()?,
);

assert!(!quick_compress.is_complete());
Source

pub fn target_volume(&self) -> PositiveReal

Get the target volume

§Example
use hoomd_geometry::shape::Rectangle;
use hoomd_mc::QuickCompress;
use hoomd_microstate::boundary::Closed;

let quick_compress = QuickCompress::<Closed<Rectangle>>::with_target_volume(
    1000.0.try_into()?,
);

let target_volume = quick_compress.target_volume();

assert_eq!(target_volume.get(), 1000.0);
Source

pub fn set_target_volume(&mut self, target_volume: PositiveReal)
where C: Clone,

Set the target volume.

Setting a new value will transition a complete QuickCompress to an active state.

§Example
use hoomd_geometry::shape::Rectangle;
use hoomd_mc::QuickCompress;
use hoomd_microstate::boundary::Closed;

let mut quick_compress =
    QuickCompress::<Closed<Rectangle>>::with_target_volume(
        1000.0.try_into()?,
    );

quick_compress.set_target_volume(500.0.try_into()?);
Source

pub fn maximum_energy_per_site(&self) -> f64

Get the maximum energy per site.

The largest energy per site allowed during apply.

§Example
use hoomd_geometry::shape::Rectangle;
use hoomd_mc::QuickCompress;
use hoomd_microstate::boundary::Closed;

let quick_compress = QuickCompress::<Closed<Rectangle>>::with_target_volume(
    1000.0.try_into()?,
);

let maximum_energy_per_site = quick_compress.maximum_energy_per_site();
Source

pub fn maximum_energy_per_site_mut(&mut self) -> &mut f64

A mutable reference to the maximum energy per site.

§Example
use hoomd_geometry::shape::Rectangle;
use hoomd_mc::QuickCompress;
use hoomd_microstate::boundary::Closed;

let mut quick_compress =
    QuickCompress::<Closed<Rectangle>>::with_target_volume(
        1000.0.try_into()?,
    );

*quick_compress.maximum_energy_per_site_mut() = 10.0;
Source

pub fn maximum_delta(&self) -> OpenUnitIntervalNumber

Get the maximum value of delta.

§Example
use hoomd_geometry::shape::Rectangle;
use hoomd_mc::QuickCompress;
use hoomd_microstate::boundary::Closed;

let quick_compress = QuickCompress::<Closed<Rectangle>>::with_target_volume(
    1000.0.try_into()?,
);

let maximum_delta = quick_compress.maximum_delta();
Source

pub fn maximum_delta_mut(&mut self) -> &mut OpenUnitIntervalNumber

A mutable reference to the maximum value of delta.

§Example
use hoomd_geometry::shape::Rectangle;
use hoomd_mc::QuickCompress;
use hoomd_microstate::boundary::Closed;

let mut quick_compress =
    QuickCompress::<Closed<Rectangle>>::with_target_volume(
        1000.0.try_into()?,
    );

*quick_compress.maximum_delta_mut() = 0.001.try_into()?;
Source

pub fn apply<P, B, S, X, H, F>( &mut self, microstate: &mut Microstate<B, S, X, C>, hamiltonian: &H, should_map_body: F, )
where P: Copy, B: Clone + Position<Position = P> + Transform<S>, S: Clone + Position<Position = P> + Default, X: Clone + PointUpdate<P, SiteKey>, H: TotalEnergy<Microstate<B, S, X, C>>, C: Clone + MapPoint<P> + Wrap<B> + Wrap<S> + GenerateGhosts<S> + Volume + Scale + PartialEq, Microstate<B, S, X, C>: Clone, F: Fn(&Tagged<Body<B, S>>) -> bool,

Apply the quick compress algorithm to a microstate.

When the total energy of the microstate (given by hamiltonian) is less than or equal to 0, apply scales the microstate’s boundary toward the target_volume by an amount $1 \pm \delta$ where $\delta$ is a randomly sampled value between 0 and maximum_delta.

should_map_body controls how bodies in the microstate are transformed. When should_map_body returns true, the body’s position will be mapped from the initial boundary to the final (via MapPoint). When should_map_body returns false, the body position is wrapped into the boundary (via Wrap).

apply then evaluates the total energy change between the initial and compressed microstates. To avoid introducing too much stress into the system, it rejects moves where the total change in energy per site is greater than maximum_energy_per_site.

Combine apply with local trial moves that translate and/or rotate bodies by small amounts to relieve the stress caused by inserting overlapping sites. Without local moves, the quick compress algorithm will not achieve the target volume.

§Example

Hard spheres

use anyhow::anyhow;

use hoomd_geometry::{Volume, shape::Rectangle};
use hoomd_interaction::{
    PairwiseCutoff,
    pairwise::Isotropic,
    univariate::{Expanded, OverlapPenalty},
};
use hoomd_mc::{QuickCompress, Sweep, Translate, Trial};
use hoomd_microstate::{
    Body, Microstate, boundary::Periodic, property::Point,
};
use hoomd_simulation::macrostate::Isothermal;
use hoomd_vector::Cartesian;

let rectangle = Rectangle::with_equal_edges(16.0.try_into()?);

let mut quick_compress = QuickCompress::with_target_volume(200.0.try_into()?);

let translate = Translate::with_maximum_distance(0.1.try_into()?);
let mut translate_sweep = Sweep(translate);

let pairwise_cutoff = PairwiseCutoff(Isotropic {
    interaction: Expanded {
        delta: 1.0,
        f: OverlapPenalty::default(),
    },
    r_cut: 1.0,
});

let macrostate = Isothermal { temperature: 1.0 };
let mut microstate = Microstate::builder()
    .boundary(Periodic::new(1.0, rectangle)?)
    .try_build()?;
for j in 0..8 {
    let y = -8.0 + j as f64 * 2.0;
    for i in 0..8 {
        let x = -8.0 + i as f64 * 2.0;
        microstate.add_body(Body::point(Cartesian::from([x, y])))?;
    }
}

while(!quick_compress.is_complete()) {
    quick_compress.apply(&mut microstate, &pairwise_cutoff, |_| true);
    translate_sweep.apply(&mut microstate, &pairwise_cutoff, &macrostate);
    microstate.increment_step();

    if microstate.step() > 10_000 {
        let current = microstate.boundary().volume();
        let target = quick_compress.target_volume();
        let step = microstate.step();
        return Err(anyhow!(
            "Achieved volume {current} after {step} steps. The target was {target}."
        ));
    }
}

Trait Implementations§

Source§

impl<C: Clone> Clone for QuickCompress<C>

Source§

fn clone(&self) -> QuickCompress<C>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<C: Debug> Debug for QuickCompress<C>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de, C> Deserialize<'de> for QuickCompress<C>
where C: Deserialize<'de>,

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<C: PartialEq> PartialEq for QuickCompress<C>

Source§

fn eq(&self, other: &QuickCompress<C>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<C> Serialize for QuickCompress<C>
where C: Serialize,

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl<C> StructuralPartialEq for QuickCompress<C>

Auto Trait Implementations§

§

impl<C> Freeze for QuickCompress<C>
where C: Freeze,

§

impl<C> RefUnwindSafe for QuickCompress<C>
where C: RefUnwindSafe,

§

impl<C> Send for QuickCompress<C>
where C: Send,

§

impl<C> Sync for QuickCompress<C>
where C: Sync,

§

impl<C> Unpin for QuickCompress<C>
where C: Unpin,

§

impl<C> UnwindSafe for QuickCompress<C>
where C: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,