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-2024.
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.numerics.atomic;
39  
40  import edu.rit.pj.IntegerForLoop;
41  import edu.rit.pj.ParallelRegion;
42  import edu.rit.pj.ParallelTeam;
43  import java.util.Arrays;
44  import java.util.logging.Level;
45  import java.util.logging.Logger;
46  
47  /**
48   * The MultiDoubleArray avoids the need for Atomic variables, but at the cost of storing a full size
49   * double array for each thread.
50   *
51   * @author Michael J. Schnieders
52   * @since 1.0
53   */
54  public class MultiDoubleArray implements AtomicDoubleArray {
55  
56    private static final Logger logger = Logger.getLogger(MultiDoubleArray.class.getName());
57  
58    private final int threadCount;
59  
60    /**
61     * Storage of the array.
62     * <p>
63     * First dimension is the thread. Second dimension is the value.
64     */
65    private final double[][] array;
66  
67    private int size;
68  
69    /**
70     * Constructor for MultiDoubleArray.
71     *
72     * @param nThreads the number of threads.
73     * @param size the size of the array.
74     */
75    public MultiDoubleArray(int nThreads, int size) {
76      this.size = size;
77      array = new double[nThreads][size];
78      threadCount = nThreads;
79    }
80  
81    /** {@inheritDoc} */
82    @Override
83    public void add(int threadID, int index, double value) {
84      array[threadID][index] += value;
85    }
86  
87    /** {@inheritDoc} */
88    @Override
89    public void alloc(int size) {
90      this.size = size;
91      for (int i = 0; i < threadCount; i++) {
92        if (array[i].length < size) {
93          array[i] = new double[size];
94        }
95      }
96    }
97  
98    /**
99     * {@inheritDoc}
100    */
101   @Override
102   public double get(int index) {
103     return array[0][index];
104   }
105 
106   /**
107    * {@inheritDoc}
108    * <p>
109    * Reduce the contributions from each thread into array[0];
110    */
111   @Override
112   public void reduce(int lb, int ub) {
113     double[] gx = array[0];
114     for (int t = 1; t < threadCount; t++) {
115       double[] gxt = array[t];
116       for (int i = lb; i <= ub; i++) {
117         gx[i] += gxt[i];
118       }
119     }
120   }
121 
122   /**
123    * {@inheritDoc}
124    * <p>
125    * Reduce the contributions from each thread into array[0];
126    */
127   @Override
128   public void reduce(ParallelTeam parallelTeam, int lb, int ub) {
129     try {
130       parallelTeam.execute(
131           new ParallelRegion() {
132             @Override
133             public void run() throws Exception {
134               execute(
135                   lb,
136                   ub,
137                   new IntegerForLoop() {
138                     @Override
139                     public void run(int first, int last) {
140                       reduce(first, last);
141                     }
142                   });
143             }
144           });
145     } catch (Exception e) {
146       logger.log(Level.WARNING, " Exception reducing an MultiDoubleArray", e);
147     }
148   }
149 
150   /**
151    * {@inheritDoc}
152    */
153   @Override
154   public void reset(int threadID, int lb, int ub) {
155     // Note that fill is appears slightly faster than arraycopy for 10,000 to 100,000 elements.
156     Arrays.fill(array[threadID], 0.0);
157     // System.arraycopy(zeros, 0, array[threadID], 0, size);
158   }
159 
160   /**
161    * {@inheritDoc}
162    */
163   @Override
164   public void reset(ParallelTeam parallelTeam, int lb, int ub) {
165     try {
166       parallelTeam.execute(
167           new ParallelRegion() {
168             @Override
169             public void run() throws Exception {
170               execute(
171                   0,
172                   threadCount - 1,
173                   new IntegerForLoop() {
174                     @Override
175                     public void run(int first, int last) {
176                       for (int i = first; i <= last; i++) {
177                         reset(i, lb, ub);
178                       }
179                     }
180                   });
181             }
182           });
183     } catch (Exception e) {
184       logger.log(Level.WARNING, " Exception resetting an MultiDoubleArray", e);
185     }
186   }
187 
188   /** {@inheritDoc} */
189   @Override
190   public void scale(int threadID, int index, double value) {
191     array[threadID][index] *= value;
192   }
193 
194   /** {@inheritDoc} */
195   @Override
196   public void set(int threadID, int index, double value) {
197     array[threadID][index] = value;
198   }
199 
200   /** {@inheritDoc} */
201   @Override
202   public int size() {
203     return size;
204   }
205 
206   /** {@inheritDoc} */
207   @Override
208   public void sub(int threadID, int index, double value) {
209     array[threadID][index] -= value;
210   }
211 }