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