def random_positions(n):
    """Returns n random 3-d vectors in a numpy array (n,3).
    d_min, d_max, npos should be in global scope"""

    import numpy as np
    from maths_module import random_vector
    import sys

    r = np.zeros((n, 3), dtype=np.float_)
    # atom 0 is always at the origin, now place the others randomly
    for i in range(1, r.shape[0]):
        for pos_try in range(npos):
            zeta = np.random.rand()
            d = d_min + (d_max - d_min) * zeta  # Magnitude of r
            r[i, :] = random_vector() * d  # In random direction
            ok = True
            for j in range(1, i):  # Check intermediate atoms if any
                d = np.sqrt(np.sum((r[i, :] - r[j, :])**2))
                ok = ok and (d >= d_min) and (d <= d_max)
            if ok:
                break
        else:
            print('Exceeded maximum number of tries in random_positions')
            sys.exit()
    return r
Example #2
0
def random_orientations(n):
    """Returns n random 3-d vectors in a numpy array (n,3)."""
    import numpy as np
    from maths_module import random_vector
    e = np.empty((n, 3), dtype=np.float_)
    for i in range(e.shape[0]):
        e[i, :] = random_vector()
    return e
Example #3
0
def chain_positions(n, bond, soft):
    """Chooses chain positions randomly, at desired bond length, avoiding overlap."""

    import numpy as np
    from maths_module import random_vector

    tol = 1.0e-9
    iter_max = 500

    print("{:40}{:15.6f}".format('Chain, randomly oriented bonds = ', bond))

    r = np.empty((n, 3), dtype=np.float_)

    r[0, :] = [0.0, 0.0, 0.0]  # First atom at origin
    r[1, :] = bond * random_vector(
    )  # Second atom at random position (bond length away)

    for i in range(2, n):  # Loop over atom indices

        iter = 0
        while True:  # Loop until non-overlapping position found
            r[i, :] = r[i - 1, :] + bond * random_vector(
            )  # Subsequent atoms randomly placed (bond length away)
            if soft:  # No overlap test
                break
            # Overlap test on all so far except bonded neighbour
            if not chain_overlap(r[i, :], r[:i - 1, :]):
                break
            iter = iter + 1
            assert iter <= iter_max, 'Too many iterations'

    r_cm = np.sum(r, axis=0) / n  # Compute centre of mass
    r = r - r_cm  # Shift centre of mass to origin

    for i in range(n - 1):
        diff_sq = np.sum((r[i, :] - r[i + 1, :])**2) - bond**2
        if np.fabs(diff_sq) > tol:
            print("{}{:5d}{:5d}{:15.8f}".format('Bond length warning', i,
                                                i + 1, diff_sq))

    return r
Example #4
0
def ran_positions(n, box, length, soft, quaternions):
    """Places atoms at random positions."""

    import numpy as np
    from maths_module import random_quaternion, random_vector

    # Unlikely to be useful, unless the interaction potential is soft
    # or the density rather low
    # For atoms, for which length=0.0, the e-coordinates will be ignored

    iter_max = 10000  # Max random placement iterations

    print('Random positions')

    r = np.empty((n, 3), dtype=np.float_)
    if quaternions:
        e = np.empty((n, 4), dtype=np.float_)
    else:
        e = np.empty((n, 3), dtype=np.float_)

    for i in range(n):

        iter = 0
        while True:  # Loop until non-overlapping position found
            r[i, :] = (np.random.rand(3) - 0.5) * box  # In range -box/2..box/2
            if quaternions:
                e[i, :] = random_quaternion()
            else:
                e[i, :] = random_vector()
            if soft:
                break
            if not overlap(r[i, :], e[i, :], r[:i, :], e[:i, :], box, length):
                break

            iter = iter + 1
            assert iter <= iter_max, "Too many iterations"

    return r, e
    "quad1_mag"]  # Quadrupole moment of molecule 1
quad2_mag = nml["quad2_mag"] if "quad2_mag" in nml else defaults[
    "quad2_mag"]  # Quadrupole moment of molecule 2

# Write out parameters
print("{:40}{:15.6f}".format('Min separation d_min', d_min))
print("{:40}{:15.6f}".format('Max separation d_max', d_max))
print("{:40}{:15.6f}".format('Dipole moment of molecule 1', mu1_mag))
print("{:40}{:15.6f}".format('Dipole moment of molecule 2', mu2_mag))
print("{:40}{:15.6f}".format('Quadrupole moment of molecule 1', quad1_mag))
print("{:40}{:15.6f}".format('Quadrupole moment of molecule 2', quad2_mag))

np.random.seed()

# Choose orientations at random
e1 = random_vector()
e2 = random_vector()

# Place atom 2 at origin and atom 1 in a random direction within desired distance range
r12_hat = random_vector()
r12_mag = np.random.rand()
r12_mag = d_min + (d_max - d_min) * r12_mag  # Magnitude of r12
r12 = r12_hat * r12_mag  # Within desired range of origin

c1 = np.dot(e1, r12_hat)  # Cosine of angle between e1 and r12
c2 = np.dot(e2, r12_hat)  # Cosine of angle between e2 and r12
c12 = np.dot(e1, e2)  # Cosine of angle between e1 and e2

print("{:40}{:10.6f}{:10.6f}{:10.6f}".format('Displacement r12', *r12))
print("{:40}{:10.6f}{:10.6f}{:10.6f}".format('Orientation e1', *e1))
print("{:40}{:10.6f}{:10.6f}{:10.6f}".format('Orientation e2', *e2))
Example #6
0
def regrow(temperature, m_max, k_max, bond, k_spring, r):
    """Carries out single regrowth move, returning new r and indicator of success."""

    # A short sequence of m atoms (m<=m_max) is deleted and regrown in the CBMC manner
    # We randomly select which end of the chain to apply each of these operations to
    # At each stage, k_max different atom positions are tried
    # Function random_bond selects bond lengths according to the internal (harmonic) potential
    # Rosenbluth weights are computed using the external (nonbonded) potential
    # Acceptance/rejection is determined using these weights

    # r_old and r_new are used as working arrays

    import numpy as np
    from maths_module import random_vector

    w_tol = 1.e-10  # Min weight tolerance
    n, d = r.shape
    assert d == 3, 'Dimension error in regrow'
    r_try = np.empty((k_max, 3), dtype=np.float_)
    w = np.empty(k_max, dtype=np.float_)

    std = np.sqrt(temperature / k_spring)  # Spring bond standard deviation
    d_max = 3.0 * std  # Impose a limit on variation, say 3*std
    assert d_max < 0.75 * bond, 'Spring bond strength error'
    d_max = d_max + bond  # This is the actual max d allowed

    r_old = np.copy(r)  # Store copy of r

    m = 1 + np.random.randint(m_max)  # Number of atoms to regrow
    c = np.random.randint(4)  # Growth option

    # PART 1: CONSTRUCT NEW CONFIGURATION WITH NEW WEIGHT

    if c == 0:  # Remove from end and add to end
        r[:n - m, :] = r_old[:n - m, :]  # Copy first n-m atoms

    elif c == 1:  # Remove from end and add to start
        r[:n - m, :] = r_old[n - m -
                             1::-1, :]  # Copy and reverse first n-m atoms

    elif c == 2:  # Remove from start and add to start
        r[:n - m, :] = r_old[:m - 1:-1, :]  # Copy and reverse last n-m atoms

    else:  # Remove from start and add to end
        r[:n - m, :] = r_old[m:, :]  # Copy last n-m atoms

    # Take the opportunity to place atom 0 at the origin
    r0 = np.copy(r[0, :])
    r[:n - m, :] = r[:n - m, :] - r0

    w_new = 1.0
    for i in range(n - m,
                   n):  # Loop to regrow last m atoms, computing new weight
        for k in range(k_max):  # Loop over k_max tries
            d = random_bond(bond, std,
                            d_max)  # Generate random bond length around d=bond
            r_try[k, :] = r[i - 1, :] + d * random_vector(
            )  # Trial position in random direction from i-1
            partial = potential_1(
                r_try[k, :],
                r[:i -
                  1, :])  # Nonbonded interactions with earlier atoms (not i-1)
            w[k] = 0.0 if partial.ovr else np.exp(
                -partial.pot / temperature)  # Weight for this try
        w_sum = np.sum(w)
        if w_sum < w_tol:  # Early exit if this happens at any stage
            return r_old, False
        w = w / w_sum
        k = np.random.choice(k_max,
                             p=w)  # Pick winning try according to weights
        r[i, :] = r_try[k, :]  # Store winning position
        w_new = w_new * w_sum  # Accumulate total weight

    if w_new < w_tol:  # Exit if this happens
        return r_old, False

    r_new = np.copy(r)  # Store new configuration

    # END OF PART 1: NEW CONFIGURATION AND WEIGHT ARE COMPLETE

    # PART 2: RECONSTRUCT OLD CONFIGURATION WITH OLD WEIGHT

    if c == 0 or c == 1:  # Remove and hence reconstruct at end
        r[:, :] = r_old[:, :]  # Copy all n atoms
    else:  # Remove and reconstruct at start
        r[:, :] = r_old[::-1, :]  # Copy and reverse all n atoms

    w_old = 1.0
    for i in range(n - m, n):

        # Old position and weight are stored as try 0
        r_try[0, :] = r[i, :]
        partial = potential_1(
            r_try[0, :],
            r[:i - 1, :])  # Nonbonded energy with earlier atoms (not i-1)
        w[0] = 0.0 if partial.ovr else np.exp(
            -partial.pot / temperature)  # Weight for this try

        # Remaining tries only required to compute weight
        for k in range(1, k_max):  # Loop over k_max-1 other tries
            d = random_bond(bond, std,
                            d_max)  # Generate random bond length around d=bond
            r_try[k, :] = r[i - 1, :] + d * random_vector(
            )  # Trial position in random direction from i-1
            partial = potential_1(
                r_try[k, :],
                r[:i -
                  1, :])  # Nonbonded interactions with earlier atoms (not i-1)
            w[k] = 0.0 if partial.ovr else np.exp(
                -partial.pot / temperature)  # Weight for this try

        w_sum = np.sum(w)
        r[i, :] = r_try[
            0, :]  # Restore winning position (always the original one)
        w_old = w_old * w_sum  # Accumulate total weight

    assert w_old > w_tol, 'Old weight error'

    # END OF PART 2: OLD CONFIGURATION AND WEIGHT ARE COMPLETE

    # Choose either old or new configuration according to weight
    # All non-bonded Boltzmann factors are incorporated into the weights
    # All spring-bond Boltzmann factors are included in the selection of d

    zeta = np.random.rand()
    if zeta < (w_new / w_old):
        return r_new, True
    else:
        return r_old, False
Example #7
0
def regrow(s, m_max, k_max, bond, q_range, r, q):
    """Carries out single regrowth move, returning new r, q and indicator of success."""

    # A short sequence of m atoms (m<=m_max) is deleted and regrown in the CBMC manner
    # We randomly select which end of the chain to apply each of these operations to
    # At each stage, k_max different atom positions are tried
    # The bond length is fixed throughout
    # Weights used in the regrowth are athermal, computed only on the basis of the
    # hard-core overlap part of the non-bonded interactions: essentially they count non-overlaps
    # Hence they are suitable for use in both NVT and Wang-Landau simulations

    # r_old and r_new are used as working arrays

    import numpy as np
    from maths_module import random_vector

    w_tol = 1.e-10  # Min weight tolerance
    n, d = r.shape
    assert d == 3, 'Dimension error in regrow'
    r_try = np.empty((k_max, 3), dtype=np.float_)
    w = np.empty(k_max, dtype=np.float_)

    r_old = np.copy(r)  # Store copy of r
    q_old = q  # Store old q

    if m_max <= 0:
        return r_old, q_old, False

    m = 1 + np.random.randint(m_max)  # Number of atoms to regrow
    c = np.random.randint(4)  # Growth option

    # PART 1: CONSTRUCT NEW CONFIGURATION WITH NEW WEIGHT

    if c == 0:  # Remove from end and add to end
        r[:n - m, :] = r_old[:n - m, :]  # Copy first n-m atoms

    elif c == 1:  # Remove from end and add to start
        r[:n - m, :] = r_old[n - m -
                             1::-1, :]  # Copy and reverse first n-m atoms

    elif c == 2:  # Remove from start and add to start
        r[:n - m, :] = r_old[:m - 1:-1, :]  # Copy and reverse last n-m atoms

    else:  # Remove from start and add to end
        r[:n - m, :] = r_old[m:, :]  # Copy last n-m atoms

    # Take the opportunity to place atom 0 at the origin
    r0 = np.copy(r[0, :])
    r[:n - m, :] = r[:n - m, :] - r0

    w_new = np.float_(1.0)
    for i in range(n - m,
                   n):  # Loop to regrow last m atoms, computing new weight
        for k in range(k_max):  # Loop over k_max tries
            r_try[k, :] = r[i - 1, :] + bond * random_vector(
            )  # Trial position in random direction from i-1
            w[k] = weight_1(r_try[k, :],
                            r[:i - 1, :])  # Store overlap weight for this try
        w_sum = np.sum(w)
        if w_sum < w_tol:  # Early exit if this happens at any stage
            return r_old, q_old, False
        w = w / w_sum
        k = np.random.choice(k_max,
                             p=w)  # Pick winning try according to weights
        r[i, :] = r_try[k, :]  # Store winning position
        w_new = w_new * w_sum  # Accumulate total weight

    if w_new < w_tol:  # Exit if this happens
        return r_old, q_old, False

    q_new = qcount(r, q_range)  # Compute full new nonbonded energy
    r_new = np.copy(r)  # Store new configuration

    # END OF PART 1: NEW CONFIGURATION AND WEIGHT ARE COMPLETE

    # PART 2: RECONSTRUCT OLD CONFIGURATION WITH OLD WEIGHT

    if c == 0 or c == 1:  # Remove and hence reconstruct at end
        r[:, :] = r_old[:, :]  # Copy all n atoms
    else:  # Remove and reconstruct at start
        r[:, :] = r_old[::-1, :]  # Copy and reverse all n atoms

    w_old = np.float_(1.0)
    for i in range(n - m, n):

        # Old position and weight are stored as try 0
        r_try[0, :] = r[i, :]
        w[0] = 1  # Current weight must be 1

        # Remaining tries only required to compute weight
        for k in range(1, k_max):  # Loop over k_max-1 other tries
            r_try[k, :] = r[i - 1, :] + bond * random_vector(
            )  # Trial position in random direction from i-1
            w[k] = weight_1(r_try[k, :],
                            r[:i - 1, :])  # Store overlap weight for this try

        w_sum = np.sum(w)
        r[i, :] = r_try[
            0, :]  # Restore winning position (always the original one)
        w_old = w_old * w_sum  # Accumulate total weight

    assert w_old > w_tol, 'Old weight error'

    # END OF PART 2: OLD CONFIGURATION AND WEIGHT ARE COMPLETE

    # Choose either old or new configuration

    if accept(s, q_old, q_new, w_old, w_new):
        return r_new, q_new, True
    else:
        return r_old, q_old, False
Example #8
0
def pivot(s, phi_max, q_range, r, q):
    """Carries out a pivot move, returning new r, q and indicator of success."""

    # An atom is picked at random, and the part of the chain lying to one side of it
    # is rotated as a whole, by a random angle, about a randomly oriented axis
    # There are no weights to take into account in the acceptance/rejection decision
    # (the function weight_1 is used simply to indicate overlap / no overlap)

    # r_old and r_new are used as working arrays

    import numpy as np
    from maths_module import random_vector, rotate_vector

    n, d = r.shape
    assert d == 3, 'Dimension error in regrow'
    if n < 3:
        return r, q, False  # Makes no sense to pivot such a short chain

    r_old = np.copy(r)  # Store copy of r
    q_old = q  # Store old q

    c = np.random.randint(2)  # Which part to pivot (actually redundant here)

    if c == 0:  # Copy atoms
        r[:, :] = r_old[:, :]

    else:  # Copy and reverse atoms
        r[:, :] = r_old[::-1, :]

    # Take the opportunity to place atom 0 at the origin
    r0 = np.copy(r[0, :])
    r = r - r0

    j = np.random.randint(1, n - 1)  # Pivot position (not at either end)
    rj = r[j, :]  # Pivot point

    for i in range(1, j +
                   1):  # Loop over static atoms, redundant but for roundoff
        if weight_1(r[i, :], r[:i - 1, :]) == 0:  # Check for overlaps
            return r_old, q_old, False

    # Pivot, and check for overlap in new configuration
    # NB include overlap checks within rotated segment, because of roundoff

    axis = random_vector()  # Pivot rotation axis
    phi = phi_max * (2.0 * np.random.rand() - 1.0
                     )  # Pivot rotation angle in desired range

    for i in range(j + 1, n):  # Loop over moving atoms

        rij = r[i, :] - rj  # Relative vector of atom
        rij = rotate_vector(phi, axis, rij)  # Rotate relative vector
        r[i, :] = rj + rij  # New absolute position

        if weight_1(r[i, :], r[:i - 1, :]) == 0:  # Check for overlaps
            return r_old, q_old, False

    q_new = qcount(r, q_range)  # Compute full new nonbonded energy
    r_new = np.copy(r)  # Store new configuration

    # Choose either old or new configuration

    if accept(s, q_old, q_new):
        return r_new, q_new, True
    else:
        return r_old, q_old, False