View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2025.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.potential.nonbonded;
39  
40  import edu.rit.pj.IntegerSchedule;
41  import edu.rit.util.Range;
42  
43  import java.util.logging.Logger;
44  
45  /**
46   * A fixed schedule that balances pairwise work across threads.
47   *
48   * @author Michael J. Schnieders
49   * @since 1.0
50   */
51  public class PairwiseSchedule extends IntegerSchedule {
52  
53    private static final Logger logger = Logger.getLogger(PairwiseSchedule.class.getName());
54    private final int nThreads;
55    private final Range[] ranges;
56    private final boolean[] threadDone;
57    private int nAtoms;
58    private int threadOffset;
59  
60    /**
61     * Constructor for PairwiseSchedule.
62     *
63     * @param nThreads a int.
64     * @param nAtoms a int.
65     * @param ranges an array of {@link edu.rit.util.Range} objects.
66     */
67    public PairwiseSchedule(int nThreads, int nAtoms, Range[] ranges) {
68      this.nAtoms = nAtoms;
69      this.nThreads = nThreads;
70      threadOffset = 0;
71      this.ranges = ranges;
72      threadDone = new boolean[nThreads];
73    }
74  
75    /**
76     * {@inheritDoc}
77     *
78     * <p>This is a fixed schedule.
79     */
80    @Override
81    public boolean isFixedSchedule() {
82      return true;
83    }
84  
85    /** {@inheritDoc} */
86    @Override
87    public Range next(int threadID) {
88      if (!threadDone[threadID]) {
89        threadDone[threadID] = true;
90        return ranges[threadID];
91      }
92      return null;
93    }
94  
95    /**
96     * setAtoms.
97     *
98     * @param nAtoms a int.
99     */
100   public void setAtoms(int nAtoms) {
101     this.nAtoms = nAtoms;
102   }
103 
104   /** {@inheritDoc} */
105   @Override
106   public void start(int nThreads, Range chunkRange) {
107     assert (nThreads == this.nThreads);
108     assert (chunkRange.lb() == 0);
109     assert (chunkRange.ub() == nAtoms - 1);
110 
111     for (int i = 0; i < nThreads; i++) {
112       threadDone[i] = false;
113     }
114   }
115 
116   /**
117    * updateRanges
118    *
119    * @param totalInteractions a int.
120    * @param atomsWithInteractions the number of chunks of interactions.
121    * @param listCount an array of int.
122    */
123   void updateRanges(int totalInteractions, int atomsWithInteractions, int[] listCount) {
124     int id = 0;
125     int goal = totalInteractions / (nThreads + threadOffset);
126     int num = 0;
127     int start = 0;
128     for (int i = 0; i < nAtoms; i++) {
129       num += listCount[i];
130       if (num >= goal) {
131 
132         // Last thread gets the remaining atoms.
133         if (id == nThreads - 1) {
134           ranges[id] = new Range(start, nAtoms - 1);
135           break;
136         }
137 
138         ranges[id] = new Range(start, i);
139 
140         // Zero out the interaction counter.
141         num = 0;
142         // Next thread.
143         id++;
144         // Next range starts at i+1.
145         start = i + 1;
146 
147         // Out of atoms. Threads remaining get a null range.
148         if (start == nAtoms) {
149           if (atomsWithInteractions > nThreads + threadOffset + 1) {
150             threadOffset++;
151             updateRanges(totalInteractions, atomsWithInteractions, listCount);
152             break;
153           }
154           for (int j = id; j < nThreads; j++) {
155             ranges[j] = null;
156           }
157           break;
158         }
159       } else if (i == nAtoms - 1) {
160 
161         // Last atom without reaching goal for current thread.
162         if (id < nThreads - 1 && atomsWithInteractions > nThreads + threadOffset + 1) {
163           threadOffset++;
164           updateRanges(totalInteractions, atomsWithInteractions, listCount);
165           break;
166         }
167         ranges[id] = new Range(start, nAtoms - 1);
168         for (int j = id + 1; j < nThreads; j++) {
169           ranges[j] = null;
170         }
171       }
172     }
173     threadOffset = 0;
174   }
175 }