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

5
6
7
8
/**
 * Perform the first step of verlet integration.
 */

9
__kernel void integrateVerletPart1(int numAtoms, __global const float2* restrict dt, __global const float4* restrict posq, __global float4* restrict velm, __global const float4* restrict force, __global float4* restrict posDelta) {
10
11
12
    float2 stepSize = dt[0];
    float dtPos = stepSize.y;
    float dtVel = 0.5f*(stepSize.x+stepSize.y);
13
14
15
    int index = get_global_id(0);
    while (index < numAtoms) {
        float4 velocity = velm[index];
16
17
18
19
20
21
22
        if (velocity.w != 0.0) {
            float4 pos = posq[index];
            velocity.xyz += force[index].xyz*dtVel*velocity.w;
            pos.xyz = velocity.xyz*dtPos;
            posDelta[index] = pos;
            velm[index] = velocity;
        }
23
24
25
26
27
28
29
30
        index += get_global_size(0);
    }
}

/**
 * Perform the second step of verlet integration.
 */

31
__kernel void integrateVerletPart2(int numAtoms, __global float2* restrict dt, __global float4* restrict posq, __global float4* restrict velm, __global const float4* restrict posDelta) {
Peter Eastman's avatar
Bug fix  
Peter Eastman committed
32
    float2 stepSize = dt[0];
33
#ifdef SUPPORTS_DOUBLE_PRECISION
34
35
    double oneOverDt = 1.0/stepSize.y;
#else
Peter Eastman's avatar
Bug fix  
Peter Eastman committed
36
    float oneOverDt = 1.0f/stepSize.y;
37
#endif
Peter Eastman's avatar
Bug fix  
Peter Eastman committed
38
39
    if (get_global_id(0) == 0)
        dt[0].x = stepSize.y;
40
    barrier(CLK_LOCAL_MEM_FENCE);
41
42
43
    int index = get_global_id(0);
    while (index < numAtoms) {
        float4 velocity = velm[index];
44
45
46
47
        if (velocity.w != 0.0) {
            float4 pos = posq[index];
            float4 delta = posDelta[index];
            pos.xyz += delta.xyz;
48
#ifdef SUPPORTS_DOUBLE_PRECISION
49
            velocity.xyz = convert_float4(convert_double4(delta)*oneOverDt).xyz;
50
#else
51
            velocity.xyz = delta.xyz*oneOverDt;
52
#endif
53
54
55
            posq[index] = pos;
            velm[index] = velocity;
        }
56
57
58
        index += get_global_size(0);
    }
}
59
60
61
62
63

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

64
__kernel void selectVerletStepSize(int numAtoms, float maxStepSize, float errorTol, __global float2* restrict dt, __global const float4* restrict velm, __global const float4* restrict force, __local float* restrict error) {
65
66
67
    // Calculate the error.

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

    // Sum the errors from all threads.

80
    for (unsigned int offset = 1; offset < get_local_size(0); offset *= 2) {
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
        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_local_id(0) == 0) {
        float totalError = sqrt(error[0]/(numAtoms*3));
        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;
    }
}