CpuLCPOForce.h 7.76 KB
Newer Older
Evan Pretti's avatar
Evan Pretti committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#ifndef OPENMM_CPULCPOFORCE_H_
#define OPENMM_CPULCPOFORCE_H_

/* -------------------------------------------------------------------------- *
 *                                   OpenMM                                   *
 * -------------------------------------------------------------------------- *
 * This is part of the OpenMM molecular simulation toolkit.                   *
 * See https://openmm.org/development.                                        *
 *                                                                            *
 * Portions copyright (c) 2025 Stanford University and the Authors.           *
 * Authors: Evan Pretti                                                       *
 * Contributors:                                                              *
 *                                                                            *
 * Permission is hereby granted, free of charge, to any person obtaining a    *
 * copy of this software and associated documentation files (the "Software"), *
 * to deal in the Software without restriction, including without limitation  *
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
 * and/or sell copies of the Software, and to permit persons to whom the      *
 * Software is furnished to do so, subject to the following conditions:       *
 *                                                                            *
 * The above copyright notice and this permission notice shall be included in *
 * all copies or substantial portions of the Software.                        *
 *                                                                            *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
 * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
 * -------------------------------------------------------------------------- */

#include <map>
#include <vector>

#include "CpuNeighborList.h"
#include "openmm/internal/vectorize.h"

namespace OpenMM {

/**
 * Performs energy, force, and charge derivative calculations for the CPU kernel
 * for LCPOForce.
 */
class CpuLCPOForce {
private:
    /**
     * Holds data about a neighbor pair (overlap areas for each sphere in the
     * last component of each fvec4 following their derivative vectors).
     */
    struct NeighborData {
        fvec4 ijData;
        fvec4 jiData;
    };

    /**
     * Holds information from a thread's request to record a neighbor.
     */
    struct NeighborInfo {
        int i, j;
        NeighborData data;
    };

    /**
     * Keeps track of neighbors for CpuLCPOForce.
     */
    class Neighbors {
    private:
        int numParticles;
        int maxNumNeighbors;
        int maxNumNeighborsFound;
        std::vector<int> numNeighbors;
        std::vector<int> indices;
        std::vector<NeighborData> data;

    public:
        /**
         * Creates an empty CpuLCPOForce::Neighbors.
         *
         * @param numParticles     the number of particles to track (this will be numActiveParticles of the parent CpuLCPOForce)
         * @param maxNumNeighbors  an initial guess for the maximum number of neighbors per particle
         */
        Neighbors(int numParticles, int maxNumNeighborsGuess = 0);

        /**
         * Clears all neighbor data.
         */
        void clear();

        /**
         * Records that two particles are neighbors of each other.  This may
         * fail silently if there is not enough room for the neighbor list.
         *
         * @param info  neighbor information recorded by a worker thread.
         */
        void insert(const NeighborInfo& info);

        /**
         * Retrieves the neighbors of a particle.
         *
         * @param i              the index of the particle
         * @param iNumNeighbors  the number of neighbors of the particle
         * @param iIndices       pointer to the start of the indices of the neighbors
         * @param iData          pointer to the start of the data associated with the neighbors
         */
        void getNeighbors(int i, int& iNumNeighbors, const int*& iIndices, const NeighborData*& iData) const;

        /**
         * Tests whether a particle is a neighbor of another particle.
         *
         * @param i          the index of the first particle
         * @param j          the index of the second particle
         * @param[out] data  data for the pair (only set if they are neighbors)
         * @return           whether or not the second particle is a neighbor of the first
         */
        bool isNeighbor(int i, int j, NeighborData& data);

        /**
         * Checks whether or not the neighbor list overflowed (and one more more
         * insertions failed) since the list was last cleared.
         *
         * @param maxNumNeighborsNeeded  the maximum number of neighbors per particle needed to avoid overflowing
         */
        bool didOverflow(int& maxNumNeighborsNeeded) {
            maxNumNeighborsNeeded = maxNumNeighborsFound;
            return maxNumNeighborsFound > maxNumNeighbors;
        }
    };

public:
    /**
     * Creates a CpuLCPOForce.
     *
     * @param threads          thread pool for computations
     * @param activeParticles  system particle indices for each active particle
     * @param parameters       parameters (radius, P2, P3, and P4) for each active particle
     * @param usePeriodic      whether or not to use periodic boundary conditions
     */
    CpuLCPOForce(ThreadPool& threads, const std::vector<int>& activeParticles, const std::vector<fvec4>& parameters, bool usePeriodic);

    /**
     * Indicates that the radii of some particles may have changed and that the
     * maximum required cutoff distance should be updated.
     */
    void updateRadii();

    /**
     * Computes energies and forces.
     *
     * @param boxVectors     periodic box vectors
     * @param posq           particle positions
     * @param threadForce    thread force accumulators
     * @param includeForces  whether or not to calculate interaction forces
     * @param includeEnergy  whether or not to calculate interaction energies
     * @param energy         energy accumulator
     */
    void execute(Vec3* boxVectors, AlignedArray<float>& posq, std::vector<AlignedArray<float> >& threadForce, bool includeForces, bool includeEnergy, double& energy);

private:
    /**
     * Thread worker for computing energies and forces.
     */
    void threadExecute(ThreadPool& threads, int threadIndex);

    /**
     * Helper for processing a block of the neighbor list.
     */
    template<bool USE_PERIODIC, bool IS_TRICLINIC>
    void processNeighborListBlock(int blockIndex, std::vector<NeighborInfo>& threadNeighborInfo);

private:
    static const int RadiusIndex = 0;
    static const int P2Index = 1;
    static const int P3Index = 2;
    static const int P4Index = 3;

    int numActiveParticles;

    ThreadPool& threads;
    const std::vector<int>& activeParticles;
    const std::vector<fvec4>& parameters;
    bool usePeriodic, isTriclinic;

    CpuNeighborList neighborList;
    std::vector<std::set<int> > exclusions;
    Neighbors neighbors;
    float cutoff;
    Vec3* boxVectors;
    fvec4 boxSize, recipBoxSize, boxVec4[3];

    float* posq;
    std::vector<double> threadEnergy;
    std::vector<AlignedArray<float> >* threadForce;
    std::vector<std::vector<NeighborInfo> > threadNeighbors;
    std::atomic<int> atomicCounter;
};

} // namespace OpenMM

#endif // OPENMM_CPULCPOFORCE_H_