def __init__(self, rc=7.0, width=1.0): """ TIP4P potential for water. http://dx.doi.org/10.1063/1.445869 Requires an atoms object of OHH,OHH, ... sequence Correct TIP4P charges and LJ parameters set automatically. Virtual interaction sites implemented in the following scheme: Original atoms object has no virtual sites. When energy/forces are requested: * virtual sites added to temporary xatoms object * energy / forces calculated * forces redistributed from virtual sites to actual atoms object This means you do not get into trouble when propagating your system with MD while having to skip / account for massless virtual sites. This also means that if using for QM/MM MD with GPAW, the EmbedTIP4P class must be used. """ TIP3P.__init__(self, rc, width) self.energy = None self.forces = None
def test_combine_mm2(): # More biased initial positions for faster test. Set # to false for a slower, harder test. fast_test = True atoms = make_4mer() atoms.constraints = FixBondLengths([(3 * i + j, 3 * i + (j + 1) % 3) for i in range(int(len(atoms) // 3)) for j in [0, 1, 2]]) atoms.calc = TIP3P(np.Inf) tag = '4mer_tip3_opt.' opt = FIRE(atoms, logfile=tag + 'log', trajectory=tag + 'traj') opt.run(fmax=0.05) tip3_pos = atoms.get_positions() sig = np.array([sigma0, 0, 0]) eps = np.array([epsilon0, 0, 0]) rc = np.Inf idxes = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], list(range(6)), list(range(9)), list(range(6, 12))] for ii, idx in enumerate(idxes): atoms = make_4mer() if fast_test: atoms.set_positions(tip3_pos) atoms.constraints = FixBondLengths([(3 * i + j, 3 * i + (j + 1) % 3) for i in range(len(atoms) // 3) for j in [0, 1, 2]]) atoms.calc = CombineMM(idx, 3, 3, TIP3P(rc), TIP3P(rc), sig, eps, sig, eps, rc=rc) tag = '4mer_combtip3_opt_{0:02d}.'.format(ii) opt = FIRE(atoms, logfile=tag + 'log', trajectory=tag + 'traj') opt.run(fmax=0.05) assert ((abs(atoms.positions - tip3_pos) < 1e-8).all()) print('{0}: {1!s:>28s}: Same Geometry as TIP3P'.format( atoms.calc.name, idx))
def make_dimer(constraint=True): """Prepare atoms object for testing""" dimer = s22.create_s22_system("Water_dimer") calc = TIP3P(rc=9.0) dimer.calc = calc if constraint: dimer.constraints = FixBondLengths([(3 * i + j, 3 * i + (j + 1) % 3) for i in range(2) for j in [0, 1, 2]]) return dimer
def test_water_dimer(internal, order): internal = True order = 0 rng = np.random.RandomState(1) atoms = atoms_ref.copy() atoms.calc = TIP3P() atoms.rattle(0.01, rng=rng) nwater = len(atoms) // 3 cons = Constraints(atoms) for i in range(nwater): cons.fix_bond((3 * i, 3 * i + 1), target=rOH) cons.fix_bond((3 * i, 3 * i + 2), target=rOH) cons.fix_angle((3 * i + 1, 3 * i, 3 * i + 2), target=angleHOH) # Remove net translation and rotation try: cons.fix_translation() except DuplicateConstraintError: pass try: cons.fix_rotation() except DuplicateConstraintError: pass sella_kwargs = dict( order=order, trajectory='test.traj', eta=1e-6, delta0=1e-2, ) if internal: sella_kwargs['internal'] = Internals(atoms, cons=cons, allow_fragments=True) else: sella_kwargs['constraints'] = cons opt = Sella(atoms, **sella_kwargs) opt.delta = 0.05 opt.run(fmax=1e-3) print("First run done") atoms.rattle() opt.run(fmax=1e-3) Ufree = opt.pes.get_Ufree() g = opt.pes.get_g() @ Ufree np.testing.assert_allclose(g, 0, atol=1e-3) opt.pes.diag(gamma=1e-16) H = opt.pes.get_HL().project(Ufree) assert np.sum(H.evals < 0) == order, H.evals
def test_rattle(): i = LJInteractions({('O', 'O'): (epsilon0, sigma0)}) for calc in [ TIP3P(), SimpleQMMM([0, 1, 2], TIP3P(), TIP3P(), TIP3P()), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), i) ]: dimer = s22('Water_dimer') for m in [0, 3]: dimer.set_angle(m + 1, m, m + 2, angleHOH) dimer.set_distance(m, m + 1, rOH, fix=0) dimer.set_distance(m, m + 2, rOH, fix=0) fixOH1 = [(3 * i, 3 * i + 1) for i in range(2)] fixOH2 = [(3 * i, 3 * i + 2) for i in range(2)] fixHH = [(3 * i + 1, 3 * i + 2) for i in range(2)] dimer.set_constraint(FixBondLengths(fixOH1 + fixOH2 + fixHH)) dimer.calc = calc e = dimer.get_potential_energy() md = VelocityVerlet(dimer, 8.0 * units.fs, trajectory=calc.name + '.traj', logfile=calc.name + '.log', loginterval=5) md.run(25) de = dimer.get_potential_energy() - e assert abs(de - -0.028) < 0.001
def test_turbomole_qmmm(): """Test the Turbomole calculator in simple QMMM and explicit interaction QMMM simulations.""" r = rOH a = angleHOH * pi / 180 D = np.linspace(2.5, 3.5, 30) interaction = LJInteractions({('O', 'O'): (epsilon0, sigma0)}) qm_par = {'esp fit': 'kollman', 'multiplicity': 1} for calc in [ TIP3P(), SimpleQMMM([0, 1, 2], Turbomole(**qm_par), TIP3P(), TIP3P()), SimpleQMMM([0, 1, 2], Turbomole(**qm_par), TIP3P(), TIP3P(), vacuum=3.0), EIQMMM([0, 1, 2], Turbomole(**qm_par), TIP3P(), interaction), EIQMMM([3, 4, 5], Turbomole(**qm_par), TIP3P(), interaction, vacuum=3.0), EIQMMM([0, 1, 2], Turbomole(**qm_par), TIP3P(), interaction, vacuum=3.0) ]: dimer = Atoms('H2OH2O', [(r * cos(a), 0, r * sin(a)), (r, 0, 0), (0, 0, 0), (r * cos(a / 2), r * sin(a / 2), 0), (r * cos(a / 2), -r * sin(a / 2), 0), (0, 0, 0)]) dimer.calc = calc E = [] F = [] for d in D: dimer.positions[3:, 0] += d - dimer.positions[5, 0] E.append(dimer.get_potential_energy()) F.append(dimer.get_forces()) F = np.array(F) F1 = np.polyval(np.polyder(np.polyfit(D, E, 7)), D) F2 = F[:, :3, 0].sum(1) error = abs(F1 - F2).max() assert error < 0.9 dimer.set_constraint( FixInternals(bonds=[(r, (0, 2)), (r, (1, 2)), (r, (3, 5)), (r, (4, 5))], angles_deg=[(angleHOH, (0, 2, 1)), (angleHOH, (3, 5, 4))])) opt = BFGS(dimer, trajectory=calc.name + '.traj', logfile=calc.name + 'd.log') opt.run(0.01) e0 = dimer.get_potential_energy() d0 = dimer.get_distance(2, 5) R = dimer.positions v1 = R[1] - R[5] v2 = R[5] - (R[3] + R[4]) / 2 a0 = np.arccos( np.dot(v1, v2) / (np.dot(v1, v1) * np.dot(v2, v2))**0.5) / np.pi * 180 fmt = '{0:>20}: {1:.3f} {2:.3f} {3:.3f} {4:.1f}' print(fmt.format(calc.name, -min(E), -e0, d0, a0))
from ase.md.langevin import Langevin from ase.io import Trajectory import ase.units as u md_cls_and_kwargs = [ (VelocityVerlet, {}), (Langevin, { "temperature": 300 * u.kB, "friction": 0.02 }), ] # prepare atoms object for testing dimer = s22.create_s22_system("Water_dimer") calc = TIP3P(rc=9.0) dimer.constraints = FixBondLengths([(3 * i + j, 3 * i + (j + 1) % 3) for i in range(2) for j in [0, 1, 2]]) def fmax(forces): return np.sqrt((forces**2).sum(axis=1).max()) def test_opt(cls, atoms, calc, logfile="opt.log", trajectory="opt.traj"): """run optimization and verify that log and trajectory coincide""" # clean files to make sure the correct ones are tested for file in (*Path().glob("*.log"), *Path().glob("*.traj")): file.unlink()
atoms2 = make_atoms() atoms2.translate([0., 3, 0]) atoms2.rotate(180, 'y') atoms2.translate([3, 0, 0]) atoms += atoms2 return atoms # More biased initial positions for faster test. Set # to false for a slower, harder test. fast_test = True atoms = make_4mer() atoms.constraints = FixBondLengths([(3 * i + j, 3 * i + (j + 1) % 3) for i in range(int(len(atoms) // 3)) for j in [0, 1, 2]]) atoms.calc = TIP3P(np.Inf) tag = '4mer_tip3_opt.' opt = FIRE(atoms, logfile=tag+'log', trajectory=tag+'traj') opt.run(fmax=0.05) tip3_pos = atoms.get_positions() sig = np.array([sigma0, 0, 0 ]) eps = np.array([epsilon0, 0, 0 ]) rc = np.Inf idxes = [[0, 1, 2], [3, 4 ,5], [6, 7, 8], [9, 10, 11], list(range(6)), list(range(9)), list(range(6, 12))] for ii, idx in enumerate(idxes): atoms = make_4mer() if fast_test: atoms.set_positions(tip3_pos)
def calc(): return TIP3P(rc=9.0)
import ase.units as units from ase.calculators.tip3p import TIP3P, epsilon0, sigma0, rOH, angleHOH from ase.calculators.qmmm import SimpleQMMM, EIQMMM, LJInteractions from ase.data.s22 import create_s22_system as s22 from ase.md.verlet import VelocityVerlet from ase.constraints import FixBondLengths i = LJInteractions({('O', 'O'): (epsilon0, sigma0)}) for calc in [ TIP3P(), SimpleQMMM([0, 1, 2], TIP3P(), TIP3P(), TIP3P()), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), i) ]: dimer = s22('Water_dimer') for m in [0, 3]: dimer.set_angle(m + 1, m, m + 2, angleHOH) dimer.set_distance(m, m + 1, rOH, fix=0) dimer.set_distance(m, m + 2, rOH, fix=0) fixOH1 = [(3 * i, 3 * i + 1) for i in range(2)] fixOH2 = [(3 * i, 3 * i + 2) for i in range(2)] fixHH = [(3 * i + 1, 3 * i + 2) for i in range(2)] dimer.set_constraint(FixBondLengths(fixOH1 + fixOH2 + fixHH)) dimer.calc = calc e = dimer.get_potential_energy() md = VelocityVerlet(dimer, 2.0 * units.fs,
from __future__ import print_function from ase.data import s22 from ase.calculators.tip3p import TIP3P, epsilon0, sigma0 from ase.calculators.qmmm import EIQMMM, LJInteractions, Embedding from gpaw import GPAW # Create system atoms = s22.create_s22_system('Water_dimer') atoms.center(vacuum=4.0) # Make QM atoms selection of first water molecule: qm_idx = range(3) # Set up interaction & embedding object interaction = LJInteractions({('O', 'O'): (epsilon0, sigma0)}) embedding = Embedding(rc=0.02) # Short range analytical potential cutoff # Set up calculator atoms.calc = EIQMMM(qm_idx, GPAW(txt='qm.out'), TIP3P(), interaction, embedding=embedding, vacuum=None, # if None, QM cell = MM cell output='qmmm.log') print(atoms.get_potential_energy())
"""Test TIP3P forces.""" from math import cos, sin from ase import Atoms from ase.calculators.tip3p import TIP3P, rOH, thetaHOH, set_tip3p_charges r = rOH a = thetaHOH dimer = Atoms('H2OH2O', [(r * cos(a), 0, r * sin(a)), (r, 0, 0), (0, 0, 0), (r * cos(a / 2), r * sin(a / 2), 0), (r * cos(a / 2), -r * sin(a / 2), 0), (0, 0, 0)]) set_tip3p_charges(dimer) dimer.calc = TIP3P(rc=4.0, width=2.0) # put O-O distance in the cutoff range dimer.positions[3:, 0] += 2.8 F = dimer.get_forces() print(F) dF = dimer.calc.calculate_numerical_forces(dimer) - F print(dF) assert abs(dF).max() < 2e-6
dexp = 2.74 aexp = 27 D = np.linspace(2.5, 3.5, 30) i = LJInteractions({('O', 'O'): (epsilon0, sigma0)}) # General LJ interaction object sigma_mm = np.array([0, 0, sigma0]) epsilon_mm = np.array([0, 0, epsilon0]) sigma_qm = np.array([0, 0, sigma0]) epsilon_qm = np.array([0, 0, epsilon0]) ig = LJInteractionsGeneral(sigma_qm, epsilon_qm, sigma_mm, epsilon_mm) for calc in [ TIP3P(), SimpleQMMM([0, 1, 2], TIP3P(), TIP3P(), TIP3P()), SimpleQMMM([0, 1, 2], TIP3P(), TIP3P(), TIP3P(), vacuum=3.0), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), i), EIQMMM([3, 4, 5], TIP3P(), TIP3P(), i, vacuum=3.0), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), i, vacuum=3.0), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), ig), EIQMMM([3, 4, 5], TIP3P(), TIP3P(), ig, vacuum=3.0), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), ig, vacuum=3.0) ]: dimer = Atoms('H2OH2O', [(r * cos(a), 0, r * sin(a)), (r, 0, 0), (0, 0, 0), (r * cos(a / 2), r * sin(a / 2), 0), (r * cos(a / 2), -r * sin(a / 2), 0), (0, 0, 0)]) dimer.calc = calc E = []
from ase import Atoms from ase.calculators.tip3p import TIP3P, epsilon0, sigma0, rOH, angleHOH from ase.calculators.qmmm import SimpleQMMM, EIQMMM, LJInteractions from ase.calculators.turbomole import Turbomole from ase.constraints import FixInternals from ase.optimize import BFGS r = rOH a = angleHOH * pi / 180 D = np.linspace(2.5, 3.5, 30) interaction = LJInteractions({('O', 'O'): (epsilon0, sigma0)}) qm_par = {'esp fit': 'kollman', 'multiplicity': 1} for calc in [ TIP3P(), SimpleQMMM([0, 1, 2], Turbomole(**qm_par), TIP3P(), TIP3P()), SimpleQMMM([0, 1, 2], Turbomole(**qm_par), TIP3P(), TIP3P(), vacuum=3.0), EIQMMM([0, 1, 2], Turbomole(**qm_par), TIP3P(), interaction), EIQMMM([3, 4, 5], Turbomole(**qm_par), TIP3P(), interaction, vacuum=3.0), EIQMMM([0, 1, 2], Turbomole(**qm_par), TIP3P(),
def test_qmmm(): from math import cos, sin, pi import numpy as np # import matplotlib.pyplot as plt import ase.units as units from ase import Atoms from ase.calculators.tip3p import TIP3P, epsilon0, sigma0, rOH, angleHOH from ase.calculators.qmmm import (SimpleQMMM, EIQMMM, LJInteractions, LJInteractionsGeneral) from ase.constraints import FixInternals from ase.optimize import GPMin r = rOH a = angleHOH * pi / 180 # From https://doi.org/10.1063/1.445869 eexp = 6.50 * units.kcal / units.mol dexp = 2.74 aexp = 27 D = np.linspace(2.5, 3.5, 30) i = LJInteractions({('O', 'O'): (epsilon0, sigma0)}) # General LJ interaction object sigma_mm = np.array([0, 0, sigma0]) epsilon_mm = np.array([0, 0, epsilon0]) sigma_qm = np.array([0, 0, sigma0]) epsilon_qm = np.array([0, 0, epsilon0]) ig = LJInteractionsGeneral(sigma_qm, epsilon_qm, sigma_mm, epsilon_mm, 3) for calc in [ TIP3P(), SimpleQMMM([0, 1, 2], TIP3P(), TIP3P(), TIP3P()), SimpleQMMM([0, 1, 2], TIP3P(), TIP3P(), TIP3P(), vacuum=3.0), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), i), EIQMMM([3, 4, 5], TIP3P(), TIP3P(), i, vacuum=3.0), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), i, vacuum=3.0), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), ig), EIQMMM([3, 4, 5], TIP3P(), TIP3P(), ig, vacuum=3.0), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), ig, vacuum=3.0) ]: dimer = Atoms('H2OH2O', [(r * cos(a), 0, r * sin(a)), (r, 0, 0), (0, 0, 0), (r * cos(a / 2), r * sin(a / 2), 0), (r * cos(a / 2), -r * sin(a / 2), 0), (0, 0, 0)]) dimer.calc = calc E = [] F = [] for d in D: dimer.positions[3:, 0] += d - dimer.positions[5, 0] E.append(dimer.get_potential_energy()) F.append(dimer.get_forces()) F = np.array(F) # plt.plot(D, E) F1 = np.polyval(np.polyder(np.polyfit(D, E, 7)), D) F2 = F[:, :3, 0].sum(1) error = abs(F1 - F2).max() assert error < 0.01 dimer.constraints = FixInternals(bonds=[(r, (0, 2)), (r, (1, 2)), (r, (3, 5)), (r, (4, 5))], angles=[(a, (0, 2, 1)), (a, (3, 5, 4))]) opt = GPMin(dimer, trajectory=calc.name + '.traj', logfile=calc.name + 'd.log') opt.run(0.01) e0 = dimer.get_potential_energy() d0 = dimer.get_distance(2, 5) R = dimer.positions v1 = R[1] - R[5] v2 = R[5] - (R[3] + R[4]) / 2 a0 = np.arccos( np.dot(v1, v2) / (np.dot(v1, v1) * np.dot(v2, v2))**0.5) / np.pi * 180 fmt = '{0:>20}: {1:.3f} {2:.3f} {3:.3f} {4:.1f}' print(fmt.format(calc.name, -min(E), -e0, d0, a0)) assert abs(e0 + eexp) < 0.002 assert abs(d0 - dexp) < 0.01 assert abs(a0 - aexp) < 4 print(fmt.format('reference', 9.999, eexp, dexp, aexp))
atoms2.translate([0., 3, 0]) atoms2.rotate(180, 'y') atoms2.translate([3, 0, 0]) atoms += atoms2 return atoms # More biased initial positions for faster test. Set # to false for a slower, harder test. fast_test = True atoms = make_4mer() atoms.constraints = FixBondLengths([(3 * i + j, 3 * i + (j + 1) % 3) for i in range(int(len(atoms) // 3)) for j in [0, 1, 2]]) atoms.calc = TIP3P(np.Inf) tag = '4mer_tip3_opt.' opt = FIRE(atoms, logfile=tag + 'log', trajectory=tag + 'traj') opt.run(fmax=0.05) tip3_pos = atoms.get_positions() sig = np.array([sigma0, 0, 0]) eps = np.array([epsilon0, 0, 0]) rc = np.Inf idxes = [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], list(range(6)), list(range(9)), list(range(6, 12))] for ii, idx in enumerate(idxes): atoms = make_4mer()
eexp = 6.50 * units.kcal / units.mol dexp = 2.74 aexp = 27 D = np.linspace(2.5, 3.5, 30) i = LJInteractions({('O', 'O'): (epsilon0, sigma0)}) # General LJ interaction object sigma_mm = np.array([0, 0, sigma0]) epsilon_mm = np.array([0, 0, epsilon0]) sigma_qm = np.array([0, 0, sigma0]) epsilon_qm = np.array([0, 0, epsilon0]) ig = LJInteractionsGeneral(sigma_qm, epsilon_qm, sigma_mm, epsilon_mm, 3) for calc in [TIP3P(), SimpleQMMM([0, 1, 2], TIP3P(), TIP3P(), TIP3P()), SimpleQMMM([0, 1, 2], TIP3P(), TIP3P(), TIP3P(), vacuum=3.0), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), i), EIQMMM([3, 4, 5], TIP3P(), TIP3P(), i, vacuum=3.0), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), i, vacuum=3.0), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), ig), EIQMMM([3, 4, 5], TIP3P(), TIP3P(), ig, vacuum=3.0), EIQMMM([0, 1, 2], TIP3P(), TIP3P(), ig, vacuum=3.0)]: dimer = Atoms('H2OH2O', [(r * cos(a), 0, r * sin(a)), (r, 0, 0), (0, 0, 0), (r * cos(a / 2), r * sin(a / 2), 0), (r * cos(a / 2), -r * sin(a / 2), 0), (0, 0, 0)])
def test_combine_mm(): """Test CombineMM forces by combining tip3p and tip4p with them selves, and by combining tip3p with tip4p and testing against numerical forces. Also test LJInterationsGeneral with CombineMM """ from math import cos, sin, pi import numpy as np from ase import Atoms from ase import units from ase.calculators.counterions import AtomicCounterIon as ACI from ase.calculators.combine_mm import CombineMM from ase.calculators.qmmm import LJInteractionsGeneral from ase.calculators.tip3p import TIP3P, rOH, angleHOH from ase.calculators.tip4p import TIP4P from ase.calculators.tip3p import epsilon0 as eps3 from ase.calculators.tip3p import sigma0 as sig3 from ase.calculators.tip4p import epsilon0 as eps4 from ase.calculators.tip4p import sigma0 as sig4 def make_atoms(): r = rOH a = angleHOH * pi / 180 dimer = Atoms('H2OH2O', [(r * cos(a), 0, r * sin(a)), (r, 0, 0), (0, 0, 0), (r * cos(a / 2), r * sin(a / 2), 0), (r * cos(a / 2), -r * sin(a / 2), 0), (0, 0, 0)]) dimer = dimer[[2, 0, 1, 5, 3, 4]] # put O-O distance in the cutoff range dimer.positions[3:, 0] += 2.8 return dimer dimer = make_atoms() rc = 3.0 for (TIPnP, (eps, sig), nm) in zip([TIP3P, TIP4P], ((eps3, sig3), (eps4, sig4)), [3, 3]): dimer.calc = TIPnP(rc=rc, width=1.0) F1 = dimer.get_forces() sigma = np.array([sig, 0, 0]) epsilon = np.array([eps, 0, 0]) dimer.calc = CombineMM([0, 1, 2], nm, nm, TIPnP(rc=rc, width=1.0), TIPnP(rc=rc, width=1.0), sigma, epsilon, sigma, epsilon, rc=rc, width=1.0) F2 = dimer.get_forces() dF = F1 - F2 print(TIPnP) print(dF) assert abs(dF).max() < 1e-8 # Also check a TIP3P/TIP4P combination against numerical forces: eps1 = np.array([eps3, 0, 0]) sig1 = np.array([sig3, 0, 0]) eps2 = np.array([eps4, 0, 0]) sig2 = np.array([sig4, 0, 0]) dimer.calc = CombineMM([0, 1, 2], 3, 3, TIP3P(rc, 1.0), TIP4P(rc, 1.0), sig1, eps1, sig2, eps2, rc, 1.0) F2 = dimer.get_forces() Fn = dimer.calc.calculate_numerical_forces(dimer, 1e-7) dF = F2 - Fn print('TIP3P/TIP4P') print(dF) assert abs(dF).max() < 1e-8 # LJInteractionsGeneral with CombineMM. # As it is used within EIQMMM, but avoiding long calculations for tests. # Total system is a unit test system comprised of: # 2 Na ions playing the role of a 'QM' subsystem # 2 Na ions as the 'Counterions' # 2 Water molecules dimer.calc = [] faux_qm = Atoms('2Na', positions=np.array([[1.4, -4, 0], [1.4, 4, 0]])) ions = Atoms('2Na', positions=np.array([[1.4, 0, -4], [1.4, 0, 4]])) mmatoms = ions + dimer sigNa = 1.868 * (1.0 / 2.0)**(1.0 / 6.0) * 10 epsNa = 0.00277 * units.kcal / units.mol # ACI for atoms 0 and 1 of the MM subsystem (2 and 3 for the total system) # 1 atom 'per molecule'. The rest is TIP4P, 3 atoms per molecule: calc = CombineMM( [0, 1], 1, 3, ACI(1, epsNa, sigNa), # calc 1 TIP4P(), # calc 2 [sigNa], [epsNa], # LJs for subsystem 1 sig2, eps2, # arrays for TIP4P from earlier rc=7.5) mmatoms.calc = calc mmatoms.calc.initialize(mmatoms) # LJ arrays for the 'QM' subsystem sig_qm = np.array([sigNa, sigNa]) eps_qm = np.array([epsNa, epsNa]) # For the MM subsystem, tuple of arrays (counterion, water) sig_mm = (np.array([sigNa]), sig2) eps_mm = (np.array([epsNa]), eps2) lj = LJInteractionsGeneral(sig_qm, eps_qm, sig_mm, eps_mm, 2) ecomb, fcomb1, fcomb2 = lj.calculate(faux_qm, mmatoms, np.array([0, 0, 0])) # This should give the same result as if not using CombineMM, on a sum # of these systems: # A: All the Na atoms in the 'QM' region # B: LJInteractions between the 'QM' Na and the 'MM' Na # C: -LJinteractions between the 'MM' Na and the 'MM' Water # A: mmatoms = dimer mmatoms.calc = [] sig_qm = np.concatenate((sig_qm, sig_qm)) eps_qm = np.concatenate((eps_qm, eps_qm)) sig_mm = sig_mm[1] eps_mm = eps_mm[1] lj = LJInteractionsGeneral(sig_qm, eps_qm, sig_mm, eps_mm, 4) ea, fa1, fa2 = lj.calculate(faux_qm + ions, mmatoms, np.array([0, 0, 0])) # B: lj = LJInteractionsGeneral(sig_qm[:2], eps_qm[:2], sig_qm[:2], eps_qm[:2], 2, 2) eb, fb1, fb2, = lj.calculate(faux_qm, ions, np.array([0, 0, 0])) # C: lj = LJInteractionsGeneral(sig_qm[:2], eps_qm[:2], sig_mm, eps_mm, 2, 3) ec, fc1, fc2, = lj.calculate(ions, dimer, np.array([0, 0, 0])) assert ecomb - (ea + eb) + ec == 0
epsilon, rc=rc, width=1.0) F2 = dimer.get_forces() dF = F1 - F2 print(TIPnP) print(dF) assert abs(dF).max() < 1e-8 # Also check a TIP3P/TIP4P combination against numerical forces: eps1 = np.array([eps3, 0, 0]) sig1 = np.array([sig3, 0, 0]) eps2 = np.array([eps4, 0, 0]) sig2 = np.array([sig4, 0, 0]) dimer.calc = CombineMM([0, 1, 2], 3, 3, TIP3P(rc, 1.0), TIP4P(rc, 1.0), sig1, eps1, sig2, eps2, rc, 1.0) F2 = dimer.get_forces() Fn = dimer.calc.calculate_numerical_forces(dimer, 1e-7) dF = F2 - Fn print('TIP3P/TIP4P') print(dF) assert abs(dF).max() < 1e-8 # LJInteractionsGeneral with CombineMM. # As it is used within EIQMMM, but avoiding long calculations for tests. # Total system is a unit test system comprised of: # 2 Na ions playing the role of a 'QM' subsystem # 2 Na ions as the 'Counterions' # 2 Water molecules
[0, rOH * np.cos(x), -rOH * np.sin(x)]] atoms = Atoms('OH2', positions=pos) vol = ((18.01528 / 6.022140857e23) / (0.9982 / 1e24))**(1 / 3.) atoms.set_cell((vol, vol, vol)) atoms.center() atoms = atoms.repeat((3, 3, 3)) atoms.set_pbc(True) # RATTLE-type constraints on O-H1, O-H2, H1-H2. atoms.constraints = FixBondLengths([(3 * i + j, 3 * i + (j + 1) % 3) for i in range(3**3) for j in [0, 1, 2]]) tag = 'tip3p_27mol_equil' atoms.calc = TIP3P(rc=4.5) md = Langevin(atoms, 1 * units.fs, temperature=300 * units.kB, friction=0.01, logfile=tag + '.log') traj = Trajectory(tag + '.traj', 'w', atoms) md.attach(traj.write, interval=1) md.run(4000) # Repeat box and equilibrate further. tag = 'tip3p_216mol_equil' atoms.set_constraint() # repeat not compatible with FixBondLengths currently. atoms = atoms.repeat((2, 2, 2)) atoms.constraints = FixBondLengths([(3 * i + j, 3 * i + (j + 1) % 3)