langevin.cl 4.88 KB
Newer Older
1
enum {VelScale, ForceScale, NoiseScale, MaxParams};
2
3
4
5
6

/**
 * Perform the first step of Langevin integration.
 */

7
8
9
10
11
12
__kernel void integrateLangevinPart1(__global mixed4* restrict velm, __global const real4* restrict force, __global mixed4* restrict posDelta,
        __global const mixed* restrict paramBuffer, __global const mixed2* restrict dt, __global const float4* restrict random, unsigned int randomIndex) {
    mixed vscale = paramBuffer[VelScale];
    mixed fscale = paramBuffer[ForceScale];
    mixed noisescale = paramBuffer[NoiseScale];
    mixed stepSize = dt[0].y;
Peter Eastman's avatar
Bug fix  
Peter Eastman committed
13
    int index = get_global_id(0);
14
    randomIndex += index;
15
    while (index < NUM_ATOMS) {
16
        mixed4 velocity = velm[index];
17
        if (velocity.w != 0.0) {
18
            mixed sqrtInvMass = sqrt(velocity.w);
19
20
21
            velocity.x = vscale*velocity.x + fscale*velocity.w*force[index].x + noisescale*sqrtInvMass*random[randomIndex].x;
            velocity.y = vscale*velocity.y + fscale*velocity.w*force[index].y + noisescale*sqrtInvMass*random[randomIndex].y;
            velocity.z = vscale*velocity.z + fscale*velocity.w*force[index].z + noisescale*sqrtInvMass*random[randomIndex].z;
22
23
24
            velm[index] = velocity;
            posDelta[index] = stepSize*velocity;
        }
25
26
27
28
29
30
        randomIndex += get_global_size(0);
        index += get_global_size(0);
    }
}

/**
31
 * Perform the second step of Langevin integration.
32
33
 */

34
__kernel void integrateLangevinPart2(__global real4* restrict posq, __global real4* restrict posqCorrection, __global const mixed4* restrict posDelta, __global mixed4* restrict velm, __global const mixed2* restrict dt) {
35
#ifdef SUPPORTS_DOUBLE_PRECISION
36
37
    double invStepSize = 1.0/dt[0].y;
#else
38
    float invStepSize = 1.0f/dt[0].y;
39
    float correction = (1.0f-invStepSize*dt[0].y)/dt[0].y;
40
#endif
41
    int index = get_global_id(0);
42
    while (index < NUM_ATOMS) {
43
        mixed4 vel = velm[index];
44
        if (vel.w != 0.0) {
45
46
47
48
49
50
51
52
#ifdef USE_MIXED_PRECISION
            real4 pos1 = posq[index];
            real4 pos2 = posqCorrection[index];
            mixed4 pos = (mixed4) (pos1.x+(mixed)pos2.x, pos1.y+(mixed)pos2.y, pos1.z+(mixed)pos2.z, pos1.w);
#else
            real4 pos = posq[index];
#endif
            mixed4 delta = posDelta[index];
53
            pos.xyz += delta.xyz;
54
#ifdef SUPPORTS_DOUBLE_PRECISION
55
            vel.xyz = convert_mixed4(invStepSize*convert_double4(delta)).xyz;
56
#else
57
            vel.xyz = invStepSize*delta.xyz + correction*delta.xyz;
58
#endif
59
60
61
62
#ifdef USE_MIXED_PRECISION
            posq[index] = convert_real4(pos);
            posqCorrection[index] = (real4) (pos.x-(real) pos.x, pos.y-(real) pos.y, pos.z-(real) pos.z, 0);
#else
63
            posq[index] = pos;
64
#endif
65
66
            velm[index] = vel;
        }
67
68
69
        index += get_global_size(0);
    }
}
70
71
72
73
74

/**
 * Select the step size to use for the next step.
 */

75
76
__kernel void selectLangevinStepSize(mixed maxStepSize, mixed errorTol, mixed tau, mixed kT, __global mixed2* restrict dt,
        __global const mixed4* restrict velm, __global const real4* restrict force, __global mixed* restrict paramBuffer, __local mixed* restrict params, __local mixed* restrict error) {
77
78
    // Calculate the error.

79
    mixed err = 0.0f;
80
    unsigned int index = get_local_id(0);
81
    while (index < NUM_ATOMS) {
82
83
        real4 f = force[index];
        mixed invMass = velm[index].w;
84
        err += (f.x*f.x + f.y*f.y + f.z*f.z)*invMass*invMass;
85
86
87
88
89
90
91
        index += get_global_size(0);
    }
    error[get_local_id(0)] = err;
    barrier(CLK_LOCAL_MEM_FENCE);

    // Sum the errors from all threads.

92
    for (unsigned int offset = 1; offset < get_local_size(0); offset *= 2) {
93
94
95
96
97
98
99
        if (get_local_id(0)+offset < get_local_size(0) && (get_local_id(0)&(2*offset-1)) == 0)
            error[get_local_id(0)] += error[get_local_id(0)+offset];
        barrier(CLK_LOCAL_MEM_FENCE);
    }
    if (get_global_id(0) == 0) {
        // Select the new step size.

100
101
        mixed totalError = sqrt(error[0]/(NUM_ATOMS*3));
        mixed newStepSize = sqrt(errorTol/totalError);
102
        mixed oldStepSize = dt[0].y;
103
104
105
106
107
108
109
110
111
112
        if (oldStepSize > 0.0f)
            newStepSize = min(newStepSize, oldStepSize*2.0f); // For safety, limit how quickly dt can increase.
        if (newStepSize > oldStepSize && newStepSize < 1.1f*oldStepSize)
            newStepSize = oldStepSize; // Keeping dt constant between steps improves the behavior of the integrator.
        if (newStepSize > maxStepSize)
            newStepSize = maxStepSize;
        dt[0].y = newStepSize;

        // Recalculate the integration parameters.

113
        mixed vscale = exp(-newStepSize/tau);
114
        mixed fscale = (1-vscale)*tau;
115
        mixed noisescale = sqrt(2*kT/tau)*sqrt(0.5f*(1-vscale*vscale)*tau);
116
117
118
        params[VelScale] = vscale;
        params[ForceScale] = fscale;
        params[NoiseScale] = noisescale;
119
120
121
122
123
    }
    barrier(CLK_LOCAL_MEM_FENCE);
    if (get_local_id(0) < MaxParams)
        paramBuffer[get_local_id(0)] = params[get_local_id(0)];
}