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.utils;
39
40 import ffx.potential.MolecularAssembly;
41 import ffx.potential.bonded.Atom;
42 import ffx.potential.bonded.Polymer;
43 import ffx.potential.bonded.Residue;
44
45 import java.util.ArrayList;
46 import java.util.List;
47 import java.util.Random;
48 import java.util.logging.Logger;
49
50 import static java.lang.String.format;
51 import static java.lang.System.arraycopy;
52
53
54
55
56
57
58
59 public class Loop {
60
61 private static final Logger logger = Logger.getLogger(Loop.class.getName());
62 private final LoopClosure loopClosure;
63 private final MolecularAssembly molecularAssembly;
64 private final Random random = new Random();
65 private static final int MAX_SOLUTIONS = 16;
66 private final double[][] rN = new double[3][3];
67 private final double[][] rA = new double[3][3];
68 private final double[][] rC = new double[3][3];
69 private double[][] altCoords;
70 private boolean useAltCoords = false;
71
72
73
74
75
76
77
78
79 public Loop(MolecularAssembly molecularAssembly, int firstResidue, int endResidue) {
80 loopClosure = new LoopClosure();
81 this.molecularAssembly = molecularAssembly;
82 generateLoops(firstResidue, endResidue);
83 }
84
85
86
87
88
89
90 public Loop(MolecularAssembly molecularAssembly) {
91 loopClosure = new LoopClosure();
92 this.molecularAssembly = molecularAssembly;
93 this.altCoords = new double[molecularAssembly.getAtomArray().length][3];
94 }
95
96
97
98
99
100
101
102
103
104 public List<double[]> generateLoops(int firstResidue, int endResidue, double[] coordinates) {
105 setAltCoordinates(coordinates);
106 return generateLoops(firstResidue, endResidue);
107 }
108
109
110
111
112
113
114
115
116 public List<double[]> generateLoops(int firstResidue, int endResidue) {
117 List<Atom> backBoneAtoms = molecularAssembly.getBackBoneAtoms();
118
119 List<double[]> solutions = new ArrayList<>();
120 logger.info(format(" First residue: %d\n", firstResidue));
121 logger.info(format(" Ending residue: %d\n", endResidue));
122 for (Atom atom : backBoneAtoms) {
123 int resID = atom.getResidueNumber();
124 if (resID > endResidue) {
125
126 break;
127 }
128
129 if (resID >= firstResidue) {
130 int ir = resID - firstResidue;
131 double[] initArray;
132 if (useAltCoords) {
133 initArray = altCoords[atom.getIndex() - 1];
134 } else {
135 initArray = atom.getXYZ(null);
136 }
137
138 switch (atom.getAtomType().name) {
139 case "C" -> {
140
141 rC[ir][0] = initArray[0];
142 rC[ir][1] = initArray[1];
143 rC[ir][2] = initArray[2];
144 }
145 case "CA" -> {
146
147 rA[ir][0] = initArray[0];
148 rA[ir][1] = initArray[1];
149 rA[ir][2] = initArray[2];
150 }
151 case "N" -> {
152
153 rN[ir][0] = initArray[0];
154 rN[ir][1] = initArray[1];
155 rN[ir][2] = initArray[2];
156 }
157 }
158 }
159 }
160
161
162 var rSolnN = new double[MAX_SOLUTIONS][3][3];
163 var rSolnA = new double[MAX_SOLUTIONS][3][3];
164 var rSolnC = new double[MAX_SOLUTIONS][3][3];
165
166 var numSolutions = loopClosure.solve3PepPoly(rN[0], rA[0], rA[2], rC[2], rSolnN, rSolnA, rSolnC);
167
168 StringBuilder sb = new StringBuilder();
169 sb.append(format(" First residue: %d\n", firstResidue));
170 sb.append(format(" Ending residue: %d\n", endResidue));
171 sb.append(format(" Number of solutions: %d\n", numSolutions));
172 logger.info(sb.toString());
173
174 for (int k = 0; k < numSolutions; k++) {
175 solutions.add(getSolutionCoordinates(k, rSolnN, rSolnA, rSolnC, firstResidue, endResidue));
176 }
177
178 return solutions;
179 }
180
181
182
183
184
185
186 public double[][] getRA() {
187 return rA;
188 }
189
190
191
192
193
194
195 public double[][] getRC() {
196 return rC;
197 }
198
199
200
201
202
203
204 public double[][] getRN() {
205 return rN;
206 }
207
208 private double[] getSolutionCoordinates(int k, double[][][] rSolnN, double[][][] rSolnA,
209 double[][][] rSolnC, int startResidue, int endResidue) {
210 for (int i = 0; i < 3; i++) {
211 for (int j = 0; j < 3; j++) {
212 rN[i][j] = rSolnN[k][i][j];
213 rA[i][j] = rSolnA[k][i][j];
214 rC[i][j] = rSolnC[k][i][j];
215 }
216 }
217
218 Polymer[] newChain = molecularAssembly.getChains();
219
220 Atom[] atomArray = molecularAssembly.getAtomArray();
221 double[][] coordsArray = new double[atomArray.length][3];
222 if (useAltCoords) {
223 arraycopy(this.altCoords, 0, coordsArray, 0, coordsArray.length);
224 } else {
225 for (int i = 0; i < atomArray.length; i++) {
226 Atom a = atomArray[i];
227 coordsArray[i][0] = a.getX();
228 coordsArray[i][1] = a.getY();
229 coordsArray[i][2] = a.getZ();
230 }
231 }
232
233
234 for (int i = startResidue; i <= endResidue; i++) {
235 Residue newResidue = newChain[0].getResidue(i);
236
237
238
239 var backBoneAtoms = newResidue.getBackboneAtoms();
240 var cOffset = new double[3];
241 var nOffset = new double[3];
242 var aOffset = new double[3];
243 for (Atom backBoneAtom : backBoneAtoms) {
244 int index = backBoneAtom.getIndex() - 1;
245 switch (backBoneAtom.getAtomType().name) {
246 case "C" -> {
247 cOffset[0] = rC[i - startResidue][0] - coordsArray[index][0];
248 cOffset[1] = rC[i - startResidue][1] - coordsArray[index][1];
249 cOffset[2] = rC[i - startResidue][2] - coordsArray[index][2];
250 arraycopy(rC[i - startResidue], 0, coordsArray[index], 0, 3);
251 }
252 case "N" -> {
253 nOffset[0] = rN[i - startResidue][0] - coordsArray[index][0];
254 nOffset[1] = rN[i - startResidue][1] - coordsArray[index][1];
255 nOffset[2] = rN[i - startResidue][2] - coordsArray[index][2];
256 arraycopy(rN[i - startResidue], 0, coordsArray[index], 0, 3);
257 }
258 case "CA" -> {
259 aOffset[0] = rA[i - startResidue][0] - coordsArray[index][0];
260 aOffset[1] = rA[i - startResidue][1] - coordsArray[index][1];
261 aOffset[2] = rA[i - startResidue][2] - coordsArray[index][2];
262 arraycopy(rA[i - startResidue], 0, coordsArray[index], 0, 3);
263 }
264 default -> {
265 }
266 }
267 }
268
269
270 for (Atom backBoneAtom : backBoneAtoms) {
271 int index = backBoneAtom.getIndex() - 1;
272 switch (backBoneAtom.getAtomType().name) {
273 case "C", "N", "CA" -> {
274
275 }
276 case "O" -> {
277 coordsArray[index][0] += cOffset[0];
278 coordsArray[index][1] += cOffset[1];
279 coordsArray[index][2] += cOffset[2];
280 }
281 case "H" -> {
282 coordsArray[index][0] += nOffset[0];
283 coordsArray[index][1] += nOffset[1];
284 coordsArray[index][2] += nOffset[2];
285 }
286 default -> {
287 coordsArray[index][0] += aOffset[0];
288 coordsArray[index][1] += aOffset[1];
289 coordsArray[index][2] += aOffset[2];
290 }
291 }
292 }
293
294
295 for (Atom sideChainAtom : newResidue.getSideChainAtoms()) {
296 int index = sideChainAtom.getIndex() - 1;
297 coordsArray[index][0] += aOffset[0];
298 coordsArray[index][1] += aOffset[1];
299 coordsArray[index][2] += aOffset[2];
300 }
301 }
302
303 double[] coordsArray1D = new double[atomArray.length * 3];
304 for (int i = 0; i < atomArray.length; i++) {
305 arraycopy(coordsArray[i], 0, coordsArray1D, i * 3, 3);
306 }
307 return coordsArray1D;
308 }
309
310 private void setAltCoordinates(double[] coordinates) {
311 for (int i = 0; i < coordinates.length / 3; i++) {
312 arraycopy(coordinates, i * 3, this.altCoords[i], 0, 3);
313 }
314
315 useAltCoords = true;
316 }
317
318 private double[][] fillCoordsArray(Atom atom, double[][] coordsArray, double[] determinedXYZ) {
319 int XYZIndex = atom.getIndex() - 1;
320 coordsArray[XYZIndex][0] = determinedXYZ[0];
321 coordsArray[XYZIndex][1] = determinedXYZ[1];
322 coordsArray[XYZIndex][2] = determinedXYZ[2];
323 return coordsArray;
324 }
325 }