<div>I want to make sure I understand exactly how the equations of motions are propagated forward in cp2k, so I decided to code up my own propagator in python and propagate the positions/velocities forward in time using the forces predicted during the simulation. However either I'm doing something wrong or cp2k does not use a simple velocity verlet integrator to propagate a molecular system forward in time.</div><div><br></div><div>Does anyone know where I can find some details on this?</div><div><br></div><div>My current setup is the following:</div><div>_________________________________________________________________________________<br></div><br><div><span><span>import </span>numpy <span>as </span>np<br><span>import </span>torch<br><br><span>def </span><span>atomic_masses</span>(z):<br>    atomic_masses = torch.tensor([<span>0</span><span>,</span><span>1.008</span><span>, </span><span>4.0026</span><span>, </span><span>6.94</span><span>, </span><span>9.0122</span><span>, </span><span>10.81</span><span>, </span><span>12.011</span><span>, </span><span>14.007</span><span>, </span><span>15.999</span><span>, </span><span>18.998</span><span>, </span><span>20.180</span><span>, </span><span>22.990</span><span>, </span><span>24.305</span><span>, </span><span>26.982</span><span>, </span><span>28.085</span>])<br>    masses = atomic_masses[z.to(<span>dtype</span>=torch.int64)]<br>    <span>return </span>masses.to(<span>device</span>=z.device)<br><br><br><span>class </span>VelocityVerletIntegrator(torch.nn.Module):<br>    <span>def </span><span>__init__</span>(<span>self</span><span>,</span>dt<span>,</span>force_predictor):<br>        <span>super</span>().<span>__init__</span>()<br>        <span>self</span>.dt = dt<br>        <span>self</span>.fp = force_predictor<br>        <span>return<br></span><span><br></span><span>    def </span><span>r_step</span>(<span>self</span><span>,</span>r<span>,</span>v<span>,</span>a):<br>        dt = <span>self</span>.dt<br>        r = r + v * dt + <span>0.5 </span>* a * dt**<span>2<br></span><span>        </span><span>return </span>r<br><br>    <span>def </span><span>v_step</span>(<span>self</span><span>,</span>v<span>,</span>a<span>,</span>a_new):<br>        dt = <span>self</span>.dt<br>        v = v + <span>0.5 </span>* (a + a_new) * dt<br>        <span>return </span>v<br><br>    <span>def </span><span>forward</span>(<span>self</span><span>,</span>r<span>,</span>v<span>,</span>m<span>,</span>nsteps):<br>        fp = <span>self</span>.fp<br><br>        F = fp(r)<br>        a = F / m<br><br>        <span>for </span>i <span>in </span><span>range</span>(nsteps):<br>            r = <span>self</span>.r_step(r<span>,</span>v<span>,</span>a)<br>            F_new = fp(r)<br>            a_new = F_new / m<br>            v = <span>self</span>.v_step(v<span>,</span>a<span>,</span>a_new)<br>            a = a_new<br>        <span>return </span>r<span>,</span>v<br><br><br><span>class </span>VelocityVerletIntegrator(torch.nn.Module):<br>    <span>def </span><span>__init__</span>(<span>self</span><span>,</span>dt):<br>        <span>super</span>().<span>__init__</span>()<br>        <span>self</span>.dt = dt<br>        <span>return<br></span><span><br></span><span>    def </span><span>r_step</span>(<span>self</span><span>,</span>r<span>,</span>v<span>,</span>a):<br>        dt = <span>self</span>.dt<br>        r = r + v * dt + <span>0.5 </span>* a * dt**<span>2<br></span><span>        </span><span>return </span>r<br><br>    <span>def </span><span>v_step</span>(<span>self</span><span>,</span>v<span>,</span>a<span>,</span>a_new):<br>        dt = <span>self</span>.dt<br>        v = v + <span>0.5 </span>* (a + a_new) * dt<br>        <span>return </span>v<br><br>    <span>def </span><span>forward</span>(<span>self</span><span>,</span>r<span>,</span>v<span>,</span>m<span>,</span>a=<span>None,</span>F=<span>None,</span>F_new=<span>None</span>):<br>        <span>if </span>a <span>is None</span>: <span># This is used on the first step<br></span><span>            </span>a = F / m<br>        r_new = <span>self</span>.r_step(r<span>,</span>v<span>,</span>a)<br>        a_new = F_new / m<br>        v_new = <span>self</span>.v_step(v<span>,</span>a<span>,</span>a_new)<br>        <span>return </span>r_new<span>,</span>v_new<span>,</span>a_new<br><br><br><span>def </span><span>MDdataloader</span>(file<span>, </span>position_converter=<span>1</span><span>,</span>velocity_converter=<span>1</span><span>,</span>force_converter=<span>1</span>):<br>    data = np.load(file)<br>    R = torch.from_numpy(data[<span>'R'</span>])*position_converter<br>    V = torch.from_numpy(data[<span>'V'</span>])*velocity_converter<br>    F = torch.from_numpy(data[<span>'F'</span>])*force_converter<br>    z = torch.from_numpy(data[<span>'z'</span>])<br>    m = atomic_masses(z)<br>    <span>return </span>R<span>,</span>V<span>,</span>F<span>,</span>z<span>,</span>m<br><br><span>if </span>__name__ == <span>'__main__'</span>:<br>    torch.set_default_dtype(torch.float64)<br>    bohr = <span>5.29177208590000E-11 </span><span>#Bohr radius [m]<br></span><span>    </span>hbar = <span>1.05457162825177E-34 </span><span>#Planck constant/(2pi) [J*s]<br></span><span>    </span>Eh = <span>4.3597447222071E-18 </span><span>#Hatree energy [J]<br></span><span>    </span>am = <span>1.66053906660E-27 </span><span>#atomic mass [kg]<br></span><span>    </span>au_T = hbar / Eh <span>#[s^-1]<br></span><span><br></span><span>    #velocties are given in bohr / au_t , we want it in Angstrom/fs<br></span><span>    </span>vel_converter = bohr / au_T * <span>1e-5<br></span><span>    </span><span># Next we have forces which are given in Hartree energy / bohr, we want it in [au*Angstrom/fs^2]<br></span><span>    </span>force_converter = Eh / bohr / (am * <span>1e20</span>)<br><br>    mddata_file = <span>'/home/tue/data/MD/ethanol/ethanol.npz'<br></span><span><br></span><span>    </span>dt = <span>0.5 </span><span># [fs]<br></span><span>    </span>nsteps = <span>10000<br></span><span><br></span><span>    </span>Rt<span>,</span>Vt<span>,</span>Ft<span>,</span>z<span>,</span>m = MDdataloader(mddata_file<span>,</span><span>velocity_converter</span>=vel_converter<span>,</span><span>force_converter</span>=force_converter)<br>    r = Rt[<span>0</span>]<br>    v = Vt[<span>0</span>]<br>    a = <span>None<br></span><span><br></span><span>    </span>VVI = VelocityVerletIntegrator(dt)<br>    <span>for </span>i <span>in </span><span>range</span>(nsteps):<br>        r<span>,</span>v<span>,</span>a = VVI(r<span>,</span>v<span>,</span>m[:<span>,None</span>]<span>,</span><span>a</span>=a<span>,</span><span>F</span>=Ft[i]<span>,</span><span>F_new</span>=Ft[i+<span>1</span>])<br><br>        dr = torch.mean(torch.norm(Rt[i+<span>1</span>] - r<span>,</span><span>p</span>=<span>2</span><span>,</span><span>dim</span>=<span>1</span>))<br>        dv = torch.mean(torch.norm(Vt[i+<span>1</span>] - v<span>,</span><span>p</span>=<span>2</span><span>,</span><span>dim</span>=<span>1</span>))<br>        <span>print</span>(<span>f"</span><span>{</span>i<span>}</span><span>, dr=</span><span>{</span>dr<span>:</span><span>0.2e</span><span>}</span><span>, dv=</span><span>{</span>dv<span>:</span><span>0.2e</span><span>}</span><span>"</span>)<br><br><br></span></div><div><br></div><div><br></div><div><br></div><br>