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.IntegerForLoop;
41 import edu.rit.pj.IntegerSchedule;
42 import edu.rit.pj.ParallelRegion;
43 import ffx.crystal.Crystal;
44 import ffx.potential.bonded.Atom;
45
46 import java.nio.DoubleBuffer;
47 import java.util.logging.Level;
48
49 import static ffx.potential.nonbonded.SpatialDensityRegion.logger;
50 import static java.util.Arrays.fill;
51
52 /**
53 * The RowRegion class is used to parallelize placing onto a 3D grid
54 *
55 * <p>1) Multipoles using B-splines or
56 *
57 * <p>2) Diffraction form factors.
58 *
59 * <p>Each "row" of 3D grid (i.e. fixed values of the z and y-coordinates) is operated on by only a
60 * single thread to logically enforce atomic updates of grid magnitudes.
61 *
62 * @author Armin Avdic
63 */
64 public class RowRegion extends ParallelRegion {
65
66 public int buff = 3;
67 public boolean[][] select;
68 protected RowLoop[] rowLoop;
69 protected double[][][] coordinates;
70 int nAtoms;
71 int nSymm;
72 private int gX, gY, gZ;
73 private DoubleBuffer gridBuffer;
74 private GridInitLoop[] gridInitLoop;
75 private double initValue = 0.0;
76 private int gridSize;
77 private double[] grid;
78 private boolean rebuildList;
79 private int[][][] zyAtListBuild;
80
81 /**
82 * Constructor for RowRegion.
83 *
84 * @param gX a int.
85 * @param gY a int.
86 * @param gZ a int.
87 * @param grid the grid array.
88 * @param nSymm a int.
89 * @param threadCount a int.
90 * @param atoms an array of {@link ffx.potential.bonded.Atom} objects.
91 * @param coordinates the atomic coordinate array.
92 */
93 public RowRegion(int gX, int gY, int gZ, double[] grid,
94 int nSymm, int threadCount, Atom[] atoms, double[][][] coordinates) {
95 this.nAtoms = atoms.length;
96 this.gX = gX;
97 this.gY = gY;
98 this.gZ = gZ;
99 gridSize = gX * gY * gZ * 2;
100 this.nSymm = nSymm;
101 this.coordinates = coordinates;
102 this.grid = grid;
103 if (grid != null) {
104 gridBuffer = DoubleBuffer.wrap(grid);
105 }
106 rowLoop = new RowLoop[threadCount];
107 gridInitLoop = new GridInitLoop[threadCount];
108 for (int i = 0; i < threadCount; i++) {
109 gridInitLoop[i] = new GridInitLoop();
110 }
111 select = new boolean[nSymm][nAtoms];
112 for (int i = 0; i < nSymm; i++) {
113 fill(select[i], true);
114 }
115 zyAtListBuild = new int[nSymm][nAtoms][2];
116 rebuildList = true;
117 }
118
119 /** {@inheritDoc} */
120 @Override
121 public void finish() {
122 if (rebuildList) {
123 rowLoop[0].saveZYValues(zyAtListBuild);
124 }
125 rebuildList = false;
126 }
127
128 /**
129 * Getter for the field <code>grid</code>.
130 *
131 * @return the grid array.
132 */
133 public double[] getGrid() {
134 return grid;
135 }
136
137 /**
138 * getNatoms.
139 *
140 * @return a int.
141 */
142 public int getNatoms() {
143 return nAtoms;
144 }
145
146 /**
147 * getNsymm.
148 *
149 * @return a int.
150 */
151 public int getNsymm() {
152 return nSymm;
153 }
154
155 /**
156 * rowIndexForYZ.
157 *
158 * @param giy a int.
159 * @param giz a int.
160 * @return a int.
161 */
162 public int rowIndexForYZ(int giy, int giz) {
163 return giy + gY * giz;
164 }
165
166 /** {@inheritDoc} */
167 @Override
168 public void run() throws Exception {
169 int threadIndex = getThreadIndex();
170 RowLoop loop = rowLoop[threadIndex];
171 // This lets the same SpatialDensityLoops be used with different SpatialDensityRegions.
172 loop.setNsymm(nSymm);
173 try {
174 execute(0, gridSize - 1, gridInitLoop[threadIndex]);
175 execute(0, (gY * gZ) - 1, loop);
176 } catch (Exception e) {
177 String message = " Exception in RowRegion.";
178 logger.log(Level.SEVERE, message, e);
179 }
180 }
181
182 /**
183 * Select atoms that should be included. The default is to include all atoms, which is set up in
184 * the constructor. This function should be over-ridden by subclasses that want finer control.
185 */
186 public void selectAtoms() {
187 for (int i = 0; i < nSymm; i++) {
188 fill(select[i], true);
189 }
190 }
191
192 /**
193 * Setter for the field <code>atoms</code>.
194 *
195 * @param atoms an array of {@link ffx.potential.bonded.Atom} objects.
196 */
197 public void setAtoms(Atom[] atoms) {
198 nAtoms = atoms.length;
199 select = new boolean[nSymm][nAtoms];
200 for (int i = 0; i < nSymm; i++) {
201 fill(select[i], true);
202 }
203 }
204
205 /**
206 * Setter for the field <code>crystal</code>.
207 *
208 * @param crystal a {@link ffx.crystal.Crystal} object.
209 * @param gX a int.
210 * @param gY a int.
211 * @param gZ a int.
212 */
213 public final void setCrystal(Crystal crystal, int gX, int gY, int gZ) {
214 // this.crystal = crystal.getUnitCell();
215 this.gX = gX;
216 this.gY = gY;
217 this.gZ = gZ;
218 gridSize = gX * gY * gZ * 2;
219 }
220
221 /**
222 * setDensityLoop.
223 *
224 * @param loops an array of {@link ffx.potential.nonbonded.RowLoop} objects.
225 */
226 public void setDensityLoop(RowLoop[] loops) {
227 rowLoop = loops;
228 }
229
230 /**
231 * Setter for the field <code>initValue</code>.
232 *
233 * @param initValue a double.
234 */
235 public void setInitValue(double initValue) {
236 this.initValue = initValue;
237 }
238
239 /** {@inheritDoc} */
240 @Override
241 public void start() {
242 selectAtoms();
243 rebuildList = (rebuildList || rowLoop[0].checkList(zyAtListBuild, buff));
244 }
245
246 /**
247 * yFromRowIndex.
248 *
249 * @param i a int.
250 * @return a int.
251 */
252 public int yFromRowIndex(int i) {
253 return i % gY;
254 }
255
256 /**
257 * zFromRowIndex.
258 *
259 * @param i a int.
260 * @return a int.
261 */
262 public int zFromRowIndex(int i) {
263 return i / gY;
264 }
265
266 /**
267 * Setter for the field <code>gridBuffer</code>.
268 *
269 * @param grid a {@link java.nio.DoubleBuffer} object.
270 */
271 void setGridBuffer(DoubleBuffer grid) {
272 gridBuffer = grid;
273 }
274
275 private class GridInitLoop extends IntegerForLoop {
276
277 private final IntegerSchedule schedule = IntegerSchedule.fixed();
278
279 @Override
280 public void run(int lb, int ub) {
281 if (gridBuffer != null) {
282 // if (grid != null) {
283 for (int i = lb; i <= ub; i++) {
284 // grid[i] = initValue;
285 gridBuffer.put(i, initValue);
286 }
287 }
288 }
289
290 @Override
291 public IntegerSchedule schedule() {
292 return schedule;
293 }
294 }
295 }