langevin.cl 4.18 KB
Newer Older
1
#ifdef SUPPORTS_DOUBLE_PRECISION
2
3
4
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#endif

5
enum {VelScale, ForceScale, NoiseScale, MaxParams};
6
7
8
9
10

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

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

/**
33
 * Perform the second step of Langevin integration.
34
35
 */

36
__kernel void integrateLangevinPart2(__global float4* restrict posq, __global const float4* restrict posDelta, __global float4* restrict velm, __global const float2* restrict dt) {
37
#ifdef SUPPORTS_DOUBLE_PRECISION
38
39
    double invStepSize = 1.0/dt[0].y;
#else
40
    float invStepSize = 1.0f/dt[0].y;
41
#endif
42
    int index = get_global_id(0);
43
    while (index < NUM_ATOMS) {
44
        float4 vel = velm[index];
45
46
47
48
        if (vel.w != 0.0) {
            float4 pos = posq[index];
            float4 delta = posDelta[index];
            pos.xyz += delta.xyz;
49
#ifdef SUPPORTS_DOUBLE_PRECISION
50
            vel.xyz = convert_float4(invStepSize*convert_double4(delta)).xyz;
51
#else
52
            vel.xyz = invStepSize*delta.xyz;
53
#endif
54
55
56
            posq[index] = pos;
            velm[index] = vel;
        }
57
58
59
        index += get_global_size(0);
    }
}
60
61
62
63
64

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

65
66
__kernel void selectLangevinStepSize(float maxStepSize, float errorTol, float tau, float kT, __global float2* restrict dt,
        __global const float4* restrict velm, __global const float4* restrict force, __global float* restrict paramBuffer, __local float* restrict params, __local float* restrict error) {
67
68
69
70
    // Calculate the error.

    float err = 0.0f;
    unsigned int index = get_local_id(0);
71
    while (index < NUM_ATOMS) {
Peter Eastman's avatar
Bug fix  
Peter Eastman committed
72
        float4 f = force[index];
73
        float invMass = velm[index].w;
Peter Eastman's avatar
Bug fix  
Peter Eastman committed
74
        err += (f.x*f.x + f.y*f.y + f.z*f.z)*invMass;
75
76
77
78
79
80
81
        index += get_global_size(0);
    }
    error[get_local_id(0)] = err;
    barrier(CLK_LOCAL_MEM_FENCE);

    // Sum the errors from all threads.

82
    for (unsigned int offset = 1; offset < get_local_size(0); offset *= 2) {
83
84
85
86
87
88
89
        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.

90
        float totalError = sqrt(error[0]/(NUM_ATOMS*3));
91
92
93
94
95
96
97
98
99
100
101
102
        float newStepSize = sqrt(errorTol/totalError);
        float oldStepSize = dt[0].y;
        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.

103
104
105
106
107
108
        float vscale = exp(-newStepSize/tau);
        float fscale = (1-vscale)*tau;
        float noisescale = sqrt(2*kT/tau)*sqrt(0.5f*(1-vscale*vscale)*tau);
        params[VelScale] = vscale;
        params[ForceScale] = fscale;
        params[NoiseScale] = noisescale;
109
110
111
112
113
    }
    barrier(CLK_LOCAL_MEM_FENCE);
    if (get_local_id(0) < MaxParams)
        paramBuffer[get_local_id(0)] = params[get_local_id(0)];
}