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 package ffx.potential.nonbonded;
39
40 import ffx.crystal.Crystal;
41 import ffx.potential.MolecularAssembly;
42 import ffx.potential.bonded.Atom;
43 import org.apache.commons.configuration2.CompositeConfiguration;
44
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.HashMap;
48 import java.util.logging.Logger;
49
50 import static java.lang.Double.parseDouble;
51 import static java.lang.Integer.parseInt;
52 import static java.lang.String.format;
53 import static org.apache.commons.math3.util.FastMath.max;
54 import static org.apache.commons.math3.util.FastMath.sqrt;
55
56
57
58
59
60
61
62 public class RestrainGroups {
63
64 private static final Logger logger = Logger.getLogger(RestrainGroups.class.getName());
65
66
67 final MolecularAssembly molecularAssembly;
68
69 final Atom[] atoms;
70
71 final int nAtoms;
72
73 final int nGroups;
74
75 final int[][] groupMembers;
76
77 final int[] groupMolecule;
78
79 final double[] groupMass;
80
81 final int nRestraints;
82
83 final int[] group1;
84
85 final int[] group2;
86
87 final double[] forceConstants;
88
89 final double[] distance1;
90
91 final double[] distance2;
92
93 final boolean[] sameMolecule;
94
95
96
97
98
99
100 public RestrainGroups(MolecularAssembly molecularAssembly) {
101 this.molecularAssembly = molecularAssembly;
102 this.atoms = molecularAssembly.getAtomArray();
103 nAtoms = atoms.length;
104
105 CompositeConfiguration compositeConfiguration = molecularAssembly.getProperties();
106
107 String[] groups = compositeConfiguration.getStringArray("group");
108 if (groups == null || groups.length < 2) {
109 logger.severe(" restrain-groups requires two groups to be defined.");
110 }
111
112 String[] restrainGroups = compositeConfiguration.getStringArray("restrain-groups");
113 if (restrainGroups == null || restrainGroups.length < 1) {
114 logger.severe(" No restrain-groups property found.");
115 }
116
117 logger.fine("\n Initializing Groups");
118
119 HashMap<Integer, ArrayList<Integer>> groupMap = new HashMap<>();
120
121 for (String g : groups) {
122
123 String[] gs = g.trim().split(" +");
124
125 int groupNumber = parseInt(gs[0]) - 1;
126 ArrayList<Integer> groupAtomIDs = new ArrayList<>();
127
128 for (int i = 1; i < gs.length; i++) {
129 int start = parseInt(gs[i]);
130 if (start < 0) {
131
132 start = -start - 1;
133 i++;
134 int end = parseInt(gs[i]) - 1;
135 if (start >= nAtoms || end < start || end >= nAtoms) {
136 logger.severe(format(" Property group could not be parsed:\n %s.", g));
137 continue;
138 }
139 for (int j = start; j <= end; j++) {
140 groupAtomIDs.add(j);
141 }
142 logger.fine(format(" Group %d added atoms %d to %d.", groupNumber + 1, start + 1, end + 1));
143 } else {
144 int atomID = start - 1;
145 groupAtomIDs.add(atomID);
146 logger.fine(format(" Group %d added atom %d.", groupNumber + 1, atomID + 1));
147 }
148 groupMap.put(groupNumber, groupAtomIDs);
149 }
150 }
151
152
153 int[] molecule = molecularAssembly.getMoleculeNumbers();
154 nGroups = groupMap.size();
155 groupMembers = new int[nGroups][];
156 groupMass = new double[nGroups];
157 groupMolecule = new int[nGroups];
158 sameMolecule = new boolean[nGroups];
159 for (Integer groupNumber : groupMap.keySet()) {
160 ArrayList<Integer> members = groupMap.get(groupNumber);
161 if (groupNumber >= nGroups) {
162 logger.severe(" Please label groups from 1 to the number of groups.");
163 }
164 int groupID = groupNumber;
165 groupMembers[groupID] = new int[members.size()];
166 int mem = 0;
167 for (int member : members) {
168 groupMembers[groupID][mem++] = member;
169 }
170 logger.finer(format(" Group %d members %s.", groupID, Arrays.toString(groupMembers[groupID])));
171 int k = groupMembers[groupID][0];
172 Atom atom = atoms[k];
173 groupMass[groupID] = atom.getMass();
174 groupMolecule[groupID] = molecule[k];
175 for (int i = 1; i < groupMembers[groupID].length; i++) {
176 k = groupMembers[groupID][i];
177 atom = atoms[k];
178 groupMass[groupID] += atom.getMass();
179 if (groupMolecule[groupID] != molecule[k]) {
180 groupMolecule[groupID] = -1;
181 }
182 }
183 groupMass[groupID] = max(groupMass[groupID], 1.0);
184 }
185
186
187 logger.fine("\n Initializing Restrain-Groups");
188 nRestraints = restrainGroups.length;
189 group1 = new int[nRestraints];
190 group2 = new int[nRestraints];
191 forceConstants = new double[nRestraints];
192 distance1 = new double[nRestraints];
193 distance2 = new double[nRestraints];
194 int iRestraint = 0;
195 for (String restraint : restrainGroups) {
196 String[] values = restraint.trim().split(" +");
197 if (values.length < 3) {
198 logger.severe(format(" Property restrain-groups could not be parsed:\n %s.", restraint));
199 }
200 group1[iRestraint] = parseInt(values[0]) - 1;
201 group2[iRestraint] = parseInt(values[1]) - 1;
202 int i1 = group1[iRestraint];
203 int i2 = group2[iRestraint];
204 if (i1 >= nGroups || i2 >= nGroups) {
205 logger.severe(format(" Property restrain-groups has invalid groups:\n %s.", restraint));
206 }
207 forceConstants[iRestraint] = parseDouble(values[2]);
208 distance1[iRestraint] = 0.0;
209 distance2[iRestraint] = 0.0;
210 if (values.length > 3) {
211 distance1[iRestraint] = parseDouble(values[3]);
212 if (values.length > 4) {
213 distance2[iRestraint] = parseDouble(values[4]);
214 }
215 }
216 sameMolecule[iRestraint] = false;
217 if (groupMolecule[i1] > -1 && groupMolecule[i2] > -1) {
218 if (groupMolecule[i1] == groupMolecule[i2]) {
219 sameMolecule[iRestraint] = true;
220 }
221 }
222 logger.fine(format(" Restrain-Groups %2d %2d %8.3f %8.3f %8.3f",
223 i1 + 1, i2 + 1, forceConstants[iRestraint], distance1[iRestraint], distance2[iRestraint]));
224
225 iRestraint++;
226 }
227 logger.fine("\n");
228 }
229
230
231
232
233
234
235 public int getNumberOfGroups() {
236 return nGroups;
237 }
238
239
240
241
242
243
244
245 public int[] getGroupMembers(int group) {
246 return groupMembers[group];
247 }
248
249
250
251
252
253
254 public int[] getGroup1() {
255 return group1;
256 }
257
258
259
260
261
262
263 public int[] getGroup2() {
264 return group2;
265 }
266
267
268
269
270
271
272 public double[] getForceConstants() {
273 return forceConstants;
274 }
275
276
277
278
279
280
281 public double[] getSmallerDistance() {
282 return distance1;
283 }
284
285
286
287
288
289
290 public double[] getLargerDistance() {
291 return distance2;
292 }
293
294
295
296
297
298
299
300 public double energy(boolean gradient) {
301 double energy = 0;
302 double[] xyz = new double[3];
303 double[] dr = new double[3];
304 Crystal crystal = molecularAssembly.getCrystal();
305 for (int i = 0; i < nRestraints; i++) {
306 int i1 = group1[i];
307 int i2 = group2[i];
308
309 double xcm = 0.0;
310 double ycm = 0.0;
311 double zcm = 0.0;
312 for (int j = 0; j < groupMembers[i1].length; j++) {
313 int k = groupMembers[i1][j];
314 Atom atom = atoms[k];
315 double mass = atom.getMass();
316 atom.getXYZ(xyz);
317 xcm = xcm + xyz[0] * mass;
318 ycm = ycm + xyz[1] * mass;
319 zcm = zcm + xyz[2] * mass;
320 }
321 double mass1 = groupMass[i1];
322 double xr = xcm / mass1;
323 double yr = ycm / mass1;
324 double zr = zcm / mass1;
325
326 xcm = 0.0;
327 ycm = 0.0;
328 zcm = 0.0;
329 for (int j = 0; j < groupMembers[i2].length; j++) {
330 int k = groupMembers[i2][j];
331 Atom atom = atoms[k];
332 double mass = atom.getMass();
333 atom.getXYZ(xyz);
334 xcm = xcm + xyz[0] * mass;
335 ycm = ycm + xyz[1] * mass;
336 zcm = zcm + xyz[2] * mass;
337 }
338 double mass2 = groupMass[i2];
339 xr = xr - xcm / mass2;
340 yr = yr - ycm / mass2;
341 zr = zr - zcm / mass2;
342 double r2;
343 if (sameMolecule[i]) {
344 r2 = xr * xr + yr * yr + zr * zr;
345 } else {
346 dr[0] = xr;
347 dr[1] = yr;
348 dr[2] = zr;
349 r2 = crystal.image(dr);
350 }
351 double r = sqrt(r2);
352 double force = forceConstants[i];
353 double gf1 = distance1[i];
354 double gf2 = distance2[i];
355 double target = r;
356 if (r < gf1) {
357 target = gf1;
358 }
359 if (r > gf2) {
360 target = gf2;
361 }
362 double dt = r - target;
363 double dt2 = dt * dt;
364 double e = force * dt2;
365 energy = energy + e;
366
367 if (gradient) {
368
369 if (r == 0.0) {
370 r = 1.0;
371 }
372 double de = 2.0 * force * dt / r;
373 double dedx = de * xr;
374 double dedy = de * yr;
375 double dedz = de * zr;
376
377 for (int j = 0; j < groupMembers[i1].length; j++) {
378 int k = groupMembers[i1][j];
379 Atom atom = atoms[k];
380 double mass = atom.getMass();
381 double ratio = mass / mass1;
382 atom.addToXYZGradient(dedx * ratio, dedy * ratio, dedz * ratio);
383 }
384
385 for (int j = 0; j < groupMembers[i2].length; j++) {
386 int k = groupMembers[i2][j];
387 Atom atom = atoms[k];
388 double mass = atom.getMass();
389 double ratio = mass / mass2;
390 atom.addToXYZGradient(-dedx * ratio, -dedy * ratio, -dedz * ratio);
391 }
392 }
393 }
394 return energy;
395 }
396
397
398
399
400
401
402 public int getNumberOfRestraints() {
403 return nRestraints;
404 }
405 }