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.parameters;
39
40 import ffx.numerics.Potential;
41 import ffx.numerics.optimization.LBFGS;
42 import ffx.numerics.optimization.LineSearch;
43 import ffx.numerics.optimization.OptimizationListener;
44 import ffx.potential.bonded.AminoAcidUtils.AminoAcid3;
45 import ffx.potential.bonded.Angle;
46 import ffx.potential.bonded.AngleTorsion;
47 import ffx.potential.bonded.Atom;
48 import ffx.potential.bonded.Bond;
49 import ffx.potential.bonded.ImproperTorsion;
50 import ffx.potential.bonded.OutOfPlaneBend;
51 import ffx.potential.bonded.PiOrbitalTorsion;
52 import ffx.potential.bonded.Residue;
53 import ffx.potential.bonded.Rotamer;
54 import ffx.potential.bonded.StretchBend;
55 import ffx.potential.bonded.StretchTorsion;
56 import ffx.potential.bonded.Torsion;
57 import ffx.potential.bonded.TorsionTorsion;
58 import ffx.potential.bonded.UreyBradley;
59 import ffx.potential.parameters.MultipoleType.MultipoleFrameDefinition;
60 import ffx.potential.parameters.SoluteType.SOLUTE_RADII_TYPE;
61 import ffx.utilities.Constants;
62
63 import java.util.Arrays;
64 import java.util.HashMap;
65 import java.util.List;
66 import java.util.logging.Level;
67 import java.util.logging.Logger;
68
69 import static ffx.potential.bonded.AminoAcidUtils.AA_CB;
70 import static ffx.potential.bonded.AminoAcidUtils.AminoAcid3.ASH;
71 import static ffx.potential.bonded.AminoAcidUtils.AminoAcid3.ASP;
72 import static ffx.potential.bonded.AminoAcidUtils.AminoAcid3.CYD;
73 import static ffx.potential.bonded.AminoAcidUtils.AminoAcid3.CYS;
74 import static ffx.potential.bonded.AminoAcidUtils.AminoAcid3.GLH;
75 import static ffx.potential.bonded.AminoAcidUtils.AminoAcid3.GLU;
76 import static ffx.potential.bonded.AminoAcidUtils.AminoAcid3.HID;
77 import static ffx.potential.bonded.AminoAcidUtils.AminoAcid3.HIE;
78 import static ffx.potential.bonded.AminoAcidUtils.AminoAcid3.HIS;
79 import static ffx.potential.bonded.AminoAcidUtils.AminoAcid3.LYD;
80 import static ffx.potential.bonded.AminoAcidUtils.AminoAcid3.LYS;
81 import static ffx.potential.bonded.BondedUtils.findAtomType;
82 import static ffx.potential.parameters.MultipoleType.assignAxisAtoms;
83 import static java.lang.String.format;
84 import static org.apache.commons.math3.util.FastMath.log;
85
86
87
88
89
90
91
92
93 public class TitrationUtils {
94
95 private static final Logger logger = Logger.getLogger(TitrationUtils.class.getName());
96
97 private static final double LOG10 = log(10.0);
98
99 private static final MultipoleType aspZeroMultipoleType = new MultipoleType(MultipoleType.zeroM,
100 new int[] {0, 140, 139}, MultipoleFrameDefinition.ZTHENX, false);
101 private static final MultipoleType ashZeroMultipoleType = new MultipoleType(MultipoleType.zeroM,
102 new int[] {0, 144, 143}, MultipoleFrameDefinition.ZTHENX, false);
103
104 private static final MultipoleType gluZeroMultipoleType = new MultipoleType(MultipoleType.zeroM,
105 new int[] {0, 158, 157}, MultipoleFrameDefinition.ZTHENX, false);
106 private static final MultipoleType glhZeroMultipoleType = new MultipoleType(MultipoleType.zeroM,
107 new int[] {0, 164, 163}, MultipoleFrameDefinition.ZTHENX, false);
108
109 private static final MultipoleType hieZeroMultipoleType = new MultipoleType(MultipoleType.zeroM,
110 new int[] {0, 130, 129}, MultipoleFrameDefinition.ZTHENX, false);
111 private static final MultipoleType hidZeroMultipoleType = new MultipoleType(MultipoleType.zeroM,
112 new int[] {0, 126, 124}, MultipoleFrameDefinition.ZTHENX, false);
113
114 private static final MultipoleType lydZeroMultipoleType = new MultipoleType(MultipoleType.zeroM,
115 new int[] {0, 200, 198}, MultipoleFrameDefinition.ZTHENX, false);
116
117 private static final MultipoleType cydZeroMultipoleType = new MultipoleType(MultipoleType.zeroM,
118 new int[] {0, 49, 43}, MultipoleFrameDefinition.ZTHENX, false);
119
120 private static final PolarizeType zeroPolarizeType = new PolarizeType(0, 0.0, 0.39, 0.0,
121 new int[] {0});
122
123 private static final SoluteType zeroSoluteType = new SoluteType(0, 1.0);
124
125 private static final AtomType dummyHydrogenAtomType = new AtomType(0, 0, "H", "\"Dummy Hydrogen\"",
126 1, 1.0080, 1);
127
128 private static final BondType zeroBondType = new BondType(new int[] {0, 0}, 0.0, 1.0);
129 private static final AngleType zeroAngleType = new AngleType(new int[] {0, 0, 0}, 0.0,
130 new double[] {0.0});
131 private static final StretchBendType zeroStretchBendType = new StretchBendType(new int[] {0, 0, 0},
132 new double[] {0.0, 0.0});
133 private static final OutOfPlaneBendType zeroOutOfPlaneBendType = new OutOfPlaneBendType(
134 new int[] {0, 0, 0, 0}, 0.0);
135 private static final TorsionType zeroTorsionType = new TorsionType(new int[] {0, 0, 0, 0},
136 new double[] {0.0}, new double[] {0.0}, new int[] {0});
137 private static final PiOrbitalTorsionType zeroPiOrbitalTorsionType = new PiOrbitalTorsionType(
138 new int[] {0, 0}, 0.0);
139
140 private double proteinDielectric;
141 private boolean tanhCorrection = false;
142
143 enum AspStates {
144 ASP, ASH1, ASH2
145 }
146
147
148 private enum AspartateAtomNames {
149 CB(0, 0, 0, 0), HB2(1, 1, 1, 0), HB3(1, 1, 1, 0), CG(2, 2, 2, 0), OD1(3, 4, 3, 0), OD2(3, 3, 4,
150 0), HD1(-1, 5, -1, 1), HD2(-1, -1, 5, -1);
151
152
153
154
155 private final int offsetASP;
156
157
158
159
160
161
162 private final int offsetASH1;
163
164
165
166
167
168
169 private final int offsetASH2;
170
171 private final int tautomerDirection;
172
173 public int getOffset(AspStates state) {
174 if (state == AspStates.ASP) {
175 return offsetASP;
176 } else if (state == AspStates.ASH1) {
177 return offsetASH1;
178 } else {
179 return offsetASH2;
180 }
181 }
182
183
184
185
186
187
188
189
190 AspartateAtomNames(int offsetASP, int offsetASH1, int offsetASH2, int tautomerDirection) {
191 this.offsetASP = offsetASP;
192 this.offsetASH1 = offsetASH1;
193 this.offsetASH2 = offsetASH2;
194 this.tautomerDirection = tautomerDirection;
195 }
196 }
197
198 enum GluStates {
199 GLU, GLH1, GLH2
200 }
201
202
203 private enum GlutamateAtomNames {
204 CB(0, 0, 0, 0), HB2(1, 1, 1, 0), HB3(1, 1, 1, 0), CG(2, 2, 2, 0), HG2(3, 3, 3, 0), HG3(3, 3, 3,
205 0), CD(4, 4, 4, 0), OE1(5, 6, 5, 0), OE2(5, 5, 6, 0), HE1(-1, 7, -1, 1), HE2(-1, -1, 7, -1);
206
207
208
209
210 private final int offsetGLU;
211
212
213
214
215
216
217
218 private final int offsetGLH1;
219
220
221
222
223
224
225
226 private final int offsetGLH2;
227
228 private final int tautomerDirection;
229
230 public int getOffset(GluStates state) {
231 if (state == GluStates.GLU) {
232 return offsetGLU;
233 } else if (state == GluStates.GLH1) {
234 return offsetGLH1;
235 } else {
236 return offsetGLH2;
237 }
238 }
239
240
241
242
243
244
245
246
247 GlutamateAtomNames(int offsetGLU, int offsetGLH1, int offsetGLH2, int tautomerDirection) {
248 this.offsetGLU = offsetGLU;
249 this.offsetGLH1 = offsetGLH1;
250 this.offsetGLH2 = offsetGLH2;
251 this.tautomerDirection = tautomerDirection;
252 }
253 }
254
255 public enum LysStates {
256 LYD, LYS
257 }
258
259
260 public enum LysineAtomNames {
261 CB(0, 0), HB2(1, 1), HB3(1, 1), CG(2, 2), HG2(3, 3), HG3(3, 3), CD(4, 4), HD2(5, 5), HD3(5,
262 5), CE(6, 6), HE2(7, 7), HE3(7, 7), NZ(8, 8), HZ1(9, 9), HZ2(9, 9), HZ3(9, -1);
263
264
265
266
267 private final int offsetLYS;
268
269
270
271
272 private final int offsetLYD;
273
274 public int getOffsetLYS(LysStates state) {
275 if (state == LysStates.LYS) {
276 return offsetLYS;
277 } else {
278 return offsetLYD;
279 }
280 }
281
282
283
284
285
286
287
288 LysineAtomNames(int offsetLYS, int offsetLYD) {
289 this.offsetLYS = offsetLYS;
290 this.offsetLYD = offsetLYD;
291 }
292 }
293
294 public enum HisStates {
295 HIS, HID, HIE
296 }
297
298
299 public enum HistidineAtomNames {
300
301 CB(0, 0, 0, 0), HB2(1, 1, 1, 0), HB3(1, 1, 1, 0), CG(2, 2, 2, 0), ND1(3, 3, 3,
302 0),
303 HD1(4, 4, -1, -1), CD2(5, 5, 4, 0), HD2(6, 6, 5, 0), CE1(7, 7, 6, 0), HE1(8, 8, 7, 0), NE2(9, 9,
304 8, 0),
305 HE2(10, -1, 9, 1);
306
307
308
309
310 private final int offsetHIS;
311
312
313
314
315
316
317
318 private final int offsetHID;
319
320
321
322
323
324
325
326 private final int offsetHIE;
327
328 private final int tautomerDirection;
329
330 public int getOffsetHIS(HisStates state) {
331 if (state == HisStates.HIS) {
332 return offsetHIS;
333 } else if (state == HisStates.HID) {
334 return offsetHID;
335 } else {
336 return offsetHIE;
337 }
338 }
339
340
341
342
343
344
345
346
347 HistidineAtomNames(int offsetHIS, int offsetHID, int offsetHIE, int tautomerDirection) {
348 this.offsetHIS = offsetHIS;
349 this.offsetHID = offsetHID;
350 this.offsetHIE = offsetHIE;
351 this.tautomerDirection = tautomerDirection;
352 }
353 }
354
355 public enum CysStates {
356 CYS, CYD
357 }
358
359
360 public enum CysteineAtomNames {
361 CB(0, 0), HB2(1, 1), HB3(1, 1), SG(2, 2), HG(3, -1);
362
363
364
365
366 private final int offsetCYS;
367
368
369
370
371
372
373 private final int offsetCYD;
374
375 public int getOffsetCYS(CysStates state) {
376 if (state == CysStates.CYS) {
377 return offsetCYS;
378 } else {
379 return offsetCYD;
380 }
381 }
382
383
384
385
386
387
388
389 CysteineAtomNames(int offsetCYS, int offsetCYD) {
390 this.offsetCYS = offsetCYS;
391 this.offsetCYD = offsetCYD;
392 }
393 }
394
395
396
397
398 private final int nLysAtomNames = LysineAtomNames.values().length;
399 private final int nLysStates = LysStates.values().length;
400 private final AtomType[][] lysAtomTypes = new AtomType[nLysAtomNames][nLysStates];
401 private final MultipoleType[][] lysMultipoleTypes = new MultipoleType[nLysAtomNames][nLysStates];
402 private final PolarizeType[][] lysPolarizeTypes = new PolarizeType[nLysAtomNames][nLysStates];
403 private final VDWType[][] lysVDWTypes = new VDWType[nLysAtomNames][nLysStates];
404 private final SoluteType[][] lysSoluteTypes = new SoluteType[nLysAtomNames][nLysStates];
405
406
407
408
409 private final int nHisAtomNames = HistidineAtomNames.values().length;
410 private final int nHisStates = HisStates.values().length;
411 private final AtomType[][] hisAtomTypes = new AtomType[nHisAtomNames][nHisStates];
412 private final MultipoleType[][] hisMultipoleTypes = new MultipoleType[nHisAtomNames][nHisStates];
413 private final PolarizeType[][] hisPolarizeTypes = new PolarizeType[nHisAtomNames][nHisStates];
414 private final VDWType[][] hisVDWTypes = new VDWType[nHisAtomNames][nHisStates];
415 private final SoluteType[][] hisSoluteTypes = new SoluteType[nHisAtomNames][nHisStates];
416
417
418
419
420 private final int nAspAtomNames = AspartateAtomNames.values().length;
421 private final int nAspStates = AspStates.values().length;
422 private final AtomType[][] aspAtomTypes = new AtomType[nAspAtomNames][nAspStates];
423 private final MultipoleType[][] aspMultipoleTypes = new MultipoleType[nAspAtomNames][nAspStates];
424 private final PolarizeType[][] aspPolarizeTypes = new PolarizeType[nAspAtomNames][nAspStates];
425 private final VDWType[][] aspVDWTypes = new VDWType[nAspAtomNames][nAspStates];
426 private final SoluteType[][] aspSoluteTypes = new SoluteType[nAspAtomNames][nAspStates];
427
428
429
430
431 private final int nGluAtomNames = GlutamateAtomNames.values().length;
432 private final int nGluStates = GluStates.values().length;
433 private final AtomType[][] gluAtomTypes = new AtomType[nGluAtomNames][nGluStates];
434 private final MultipoleType[][] gluMultipoleTypes = new MultipoleType[nGluAtomNames][nGluStates];
435 private final PolarizeType[][] gluPolarizeTypes = new PolarizeType[nGluAtomNames][nGluStates];
436 private final VDWType[][] gluVDWTypes = new VDWType[nGluAtomNames][nGluStates];
437 private final SoluteType[][] gluSoluteTypes = new SoluteType[nGluAtomNames][nGluStates];
438
439
440
441
442 private final int nCysAtomNames = CysteineAtomNames.values().length;
443 private final int nCysStates = CysStates.values().length;
444 private final AtomType[][] cysAtomTypes = new AtomType[nCysAtomNames][nCysStates];
445 private final MultipoleType[][] cysMultipoleTypes = new MultipoleType[nCysAtomNames][nCysStates];
446 private final PolarizeType[][] cysPolarizeTypes = new PolarizeType[nCysAtomNames][nCysStates];
447 private final VDWType[][] cysVDWTypes = new VDWType[nCysAtomNames][nCysStates];
448 private final SoluteType[][] cysSoluteTypes = new SoluteType[nCysAtomNames][nCysStates];
449
450 private final ForceField forceField;
451 private final SOLUTE_RADII_TYPE soluteRadiiType;
452 private final boolean updateBondedTerms;
453
454 private final HashMap<AminoAcid3, Double> rotamerPhBiasMap = new HashMap<>();
455
456 public TitrationUtils(ForceField forceField) {
457 this.forceField = forceField;
458
459 String gkRadius = forceField.getString("GK_RADIUS", "SOLUTE");
460 SOLUTE_RADII_TYPE tempType;
461 try {
462 tempType = SOLUTE_RADII_TYPE.valueOf(gkRadius.trim().toUpperCase());
463 } catch (Exception e) {
464 tempType = SOLUTE_RADII_TYPE.SOLUTE;
465 }
466 soluteRadiiType = tempType;
467
468 updateBondedTerms = forceField.getBoolean("TITRATION_UPDATE_BONDED_TERMS", true);
469
470
471 constructLYSState(AA_CB[LYS.ordinal()], LysStates.LYS);
472 constructLYSState(AA_CB[LYD.ordinal()], LysStates.LYD);
473 checkParameterTypes("LYS", lysAtomTypes, lysPolarizeTypes, lysMultipoleTypes, lysVDWTypes);
474
475
476 constructHISState(AA_CB[HIS.ordinal()], HisStates.HIS);
477 constructHISState(AA_CB[HID.ordinal()], HisStates.HID);
478 constructHISState(AA_CB[HIE.ordinal()], HisStates.HIE);
479 checkParameterTypes("HIS", hisAtomTypes, hisPolarizeTypes, hisMultipoleTypes, hisVDWTypes);
480
481
482 constructASPState(AA_CB[ASP.ordinal()], AspStates.ASP);
483 constructASPState(AA_CB[ASH.ordinal()], AspStates.ASH1);
484 constructASPState(AA_CB[ASH.ordinal()], AspStates.ASH2);
485 checkParameterTypes("ASP", aspAtomTypes, aspPolarizeTypes, aspMultipoleTypes, aspVDWTypes);
486
487
488 constructGLUState(AA_CB[GLU.ordinal()], GluStates.GLU);
489 constructGLUState(AA_CB[GLH.ordinal()], GluStates.GLH1);
490 constructGLUState(AA_CB[GLH.ordinal()], GluStates.GLH2);
491 checkParameterTypes("GLU", gluAtomTypes, gluPolarizeTypes, gluMultipoleTypes, gluVDWTypes);
492
493
494 constructCYSState(AA_CB[CYS.ordinal()], CysStates.CYS);
495 constructCYSState(AA_CB[CYD.ordinal()], CysStates.CYD);
496 checkParameterTypes("CYS", cysAtomTypes, cysPolarizeTypes, cysMultipoleTypes, cysVDWTypes);
497 }
498
499 public TitrationUtils(ForceField forceField, double proteinDielectric, boolean tanhCorrection){
500 this(forceField);
501 this.proteinDielectric = proteinDielectric;
502 this.tanhCorrection = tanhCorrection;
503
504
505
506
507
508
509
510
511
512
513
514 }
515
516 public boolean testResidueTypes(Residue residue) {
517
518 boolean testPassed = true;
519 int nStates = 1;
520 AminoAcid3 aminoAcid3 = residue.getAminoAcid3();
521 switch (aminoAcid3) {
522 case ASP, ASH, ASD, GLU, GLH, GLD, HIS, HID, HIE -> nStates = 3;
523 case CYS, CYD, LYS, LYD -> nStates = 2;
524 default -> logger.info(format(" Only one state for atom %s.", aminoAcid3));
525 }
526
527 List<Atom> atomList = residue.getSideChainAtoms();
528 int nAtoms = atomList.size();
529 int[][][] axisAtomIndices = new int[nAtoms][nStates][];
530 AtomType[][] atomTypes = new AtomType[nAtoms][nStates];
531 MultipoleType[][] multipoleTypes = new MultipoleType[nAtoms][nStates];
532
533 AtomType[] initialAtomTypes = new AtomType[nAtoms];
534 MultipoleType[] initialMultipoleTypes = new MultipoleType[nAtoms];
535
536 for (int i = 0; i < nAtoms; i++) {
537 Atom atom = atomList.get(i);
538 initialAtomTypes[i] = atom.getAtomType();
539 initialMultipoleTypes[i] = atom.getMultipoleType();
540 }
541
542
543 for (int state = 0; state < nStates; state++) {
544
545 for (int i = 0; i < nAtoms; i++) {
546 Atom atom = atomList.get(i);
547 String atomName = atom.getName();
548 switch (aminoAcid3) {
549 case ASP:
550 case ASH:
551 case ASD:
552 int index = AspartateAtomNames.valueOf(atomName).ordinal();
553 atom.setAtomType(aspAtomTypes[index][state]);
554 atom.setMultipoleType(aspMultipoleTypes[index][state]);
555 break;
556 case CYS:
557 case CYD:
558 index = CysteineAtomNames.valueOf(atomName).ordinal();
559 atom.setAtomType(cysAtomTypes[index][state]);
560 atom.setMultipoleType(cysMultipoleTypes[index][state]);
561 break;
562 case GLU:
563 case GLH:
564 case GLD:
565 index = GlutamateAtomNames.valueOf(atomName).ordinal();
566 atom.setAtomType(gluAtomTypes[index][state]);
567 atom.setMultipoleType(gluMultipoleTypes[index][state]);
568 break;
569 case HIS:
570 case HID:
571 case HIE:
572 index = HistidineAtomNames.valueOf(atomName).ordinal();
573 atom.setAtomType(hisAtomTypes[index][state]);
574 atom.setMultipoleType(hisMultipoleTypes[index][state]);
575 break;
576 case LYS:
577 case LYD:
578 index = LysineAtomNames.valueOf(atomName).ordinal();
579 atom.setAtomType(lysAtomTypes[index][state]);
580 atom.setMultipoleType(lysMultipoleTypes[index][state]);
581 break;
582 default:
583 logger.info(format(" Only one state for atom %s.", atom));
584 }
585 atomTypes[i][state] = atom.getAtomType();
586 multipoleTypes[i][state] = atom.getMultipoleType();
587 }
588
589 for (int i = 0; i < nAtoms; i++) {
590 Atom atom = atomList.get(i);
591 assignAxisAtoms(atom);
592 axisAtomIndices[i][state] = atom.getAxisAtomIndices();
593 }
594 }
595
596
597 for (int i = 0; i < nAtoms; i++) {
598 Atom atom = atomList.get(i);
599 int[] referenceIndices = axisAtomIndices[i][0];
600 AtomType referenceAtomType = atomTypes[i][0];
601 MultipoleType referenceMultipoleType = multipoleTypes[i][0];
602 for (int state = 1; state < nStates; state++) {
603 int[] stateIndices = axisAtomIndices[i][state];
604 AtomType stateAtomType = atomTypes[i][state];
605 MultipoleType stateMultipoleType = multipoleTypes[i][state];
606 if (referenceMultipoleType.frameDefinition != stateMultipoleType.frameDefinition) {
607 logger.warning(format(" Local frame definition is inconsistent for atom %s", atom));
608 logger.warning(format(" %s\n %s", referenceAtomType, referenceMultipoleType));
609 logger.warning(format(" %s\n %s", stateAtomType, stateMultipoleType));
610 testPassed = false;
611 continue;
612 }
613 if (Arrays.compare(referenceIndices, stateIndices) != 0) {
614
615 if (referenceMultipoleType.frameDefinition == MultipoleFrameDefinition.BISECTOR) {
616 if (referenceIndices[0] == stateIndices[1] && referenceIndices[1] == stateIndices[0]) {
617 continue;
618 }
619 }
620 logger.warning(format(" Local frame atom indices are inconsistent for atom %s", atom));
621 logger.warning(
622 format(" %s %s\n %s", referenceAtomType, Arrays.toString(referenceIndices),
623 referenceMultipoleType));
624 logger.warning(format(" %s %s\n %s", stateAtomType, Arrays.toString(stateIndices),
625 stateMultipoleType));
626 testPassed = false;
627 }
628 }
629 }
630
631
632 for (int i = 0; i < nAtoms; i++) {
633 Atom atom = atomList.get(i);
634 atom.setAtomType(initialAtomTypes[i]);
635 atom.setMultipoleType(initialMultipoleTypes[i]);
636 }
637
638 return testPassed;
639 }
640
641
642
643
644
645
646
647
648 public void updateResidueParameters(Residue residue, Rotamer rotamer) {
649 if (!rotamer.isTitrating) {
650 return;
651 }
652
653 AminoAcid3 aminoAcid3 = residue.getAminoAcid3();
654 switch (aminoAcid3) {
655 case ASH, ASP -> {
656
657 int aspIndex = AspStates.ASP.ordinal();
658 if (rotamer.aminoAcid3 == ASH) {
659
660 aspIndex = AspStates.ASH2.ordinal();
661 }
662 for (AspartateAtomNames atomName : AspartateAtomNames.values()) {
663 if (atomName.name().equals("HD1")) {
664
665
666 continue;
667 }
668 int atomIndex = atomName.ordinal();
669 Atom atom = (Atom) residue.getAtomNode(atomName.name());
670 if (atom == null) {
671 logger.severe(" Atom is null for " + atomName);
672 return;
673 }
674 atom.setAtomType(aspAtomTypes[atomIndex][aspIndex]);
675 atom.setMultipoleType(aspMultipoleTypes[atomIndex][aspIndex]);
676 atom.setPolarizeType(aspPolarizeTypes[atomIndex][aspIndex]);
677 atom.setVDWType(aspVDWTypes[atomIndex][aspIndex]);
678 atom.setSoluteType(aspSoluteTypes[atomIndex][aspIndex]);
679 }
680 }
681 case GLU, GLH -> {
682
683 int gluIndex = GluStates.GLU.ordinal();
684 if (rotamer.aminoAcid3 == GLH) {
685
686 gluIndex = GluStates.GLH2.ordinal();
687 }
688 for (GlutamateAtomNames atomName : GlutamateAtomNames.values()) {
689 if (atomName.name().equals("HE1")) {
690
691
692 continue;
693 }
694 int atomIndex = atomName.ordinal();
695 Atom atom = (Atom) residue.getAtomNode(atomName.name());
696 if (atom == null) {
697 logger.severe(" Atom is null for " + atomName);
698 return;
699 }
700 atom.setAtomType(gluAtomTypes[atomIndex][gluIndex]);
701 atom.setMultipoleType(gluMultipoleTypes[atomIndex][gluIndex]);
702 atom.setPolarizeType(gluPolarizeTypes[atomIndex][gluIndex]);
703 atom.setVDWType(gluVDWTypes[atomIndex][gluIndex]);
704 atom.setSoluteType(gluSoluteTypes[atomIndex][gluIndex]);
705 }
706 }
707 case LYS, LYD -> {
708
709 int lysIndex = LysStates.LYS.ordinal();
710 if (rotamer.aminoAcid3 == LYD) {
711
712 lysIndex = LysStates.LYD.ordinal();
713 }
714 for (LysineAtomNames atomName : LysineAtomNames.values()) {
715 int atomIndex = atomName.ordinal();
716 Atom atom = (Atom) residue.getAtomNode(atomName.name());
717 if (atom == null) {
718 logger.severe(" Atom is null for " + atomName);
719 return;
720 }
721 atom.setAtomType(lysAtomTypes[atomIndex][lysIndex]);
722 atom.setMultipoleType(lysMultipoleTypes[atomIndex][lysIndex]);
723 atom.setPolarizeType(lysPolarizeTypes[atomIndex][lysIndex]);
724 atom.setVDWType(lysVDWTypes[atomIndex][lysIndex]);
725 atom.setSoluteType(lysSoluteTypes[atomIndex][lysIndex]);
726 }
727 }
728 case CYS, CYD -> {
729
730 int cysIndex = CysStates.CYS.ordinal();
731 if (rotamer.aminoAcid3 == CYD) {
732
733 cysIndex = CysStates.CYD.ordinal();
734 }
735 for (CysteineAtomNames atomName : CysteineAtomNames.values()) {
736 int atomIndex = atomName.ordinal();
737 Atom atom = (Atom) residue.getAtomNode(atomName.name());
738 if (atom == null) {
739 logger.severe(" Atom is null for " + atomName);
740 return;
741 }
742 atom.setAtomType(cysAtomTypes[atomIndex][cysIndex]);
743 atom.setMultipoleType(cysMultipoleTypes[atomIndex][cysIndex]);
744 atom.setPolarizeType(cysPolarizeTypes[atomIndex][cysIndex]);
745 atom.setVDWType(cysVDWTypes[atomIndex][cysIndex]);
746 atom.setSoluteType(cysSoluteTypes[atomIndex][cysIndex]);
747 }
748 }
749 case HIS, HIE, HID -> {
750
751 int hisIndex = switch (rotamer.aminoAcid3) {
752 case HIE -> HisStates.HIE.ordinal();
753 case HID -> HisStates.HID.ordinal();
754 default -> HisStates.HIS.ordinal();
755 };
756 for (HistidineAtomNames atomName : HistidineAtomNames.values()) {
757 int atomIndex = atomName.ordinal();
758 Atom atom = (Atom) residue.getAtomNode(atomName.name());
759 if (atom == null) {
760 logger.severe(" Atom is null for " + atomName);
761 return;
762 }
763 atom.setAtomType(hisAtomTypes[atomIndex][hisIndex]);
764 atom.setMultipoleType(hisMultipoleTypes[atomIndex][hisIndex]);
765 atom.setPolarizeType(hisPolarizeTypes[atomIndex][hisIndex]);
766 atom.setVDWType(hisVDWTypes[atomIndex][hisIndex]);
767 atom.setSoluteType(hisSoluteTypes[atomIndex][hisIndex]);
768 }
769 }
770 default -> logger.severe(
771 format(" No support for titrating residue %s with rotamer %s.", residue, rotamer));
772 }
773
774
775 for (Atom atom : residue.getSideChainAtoms()) {
776 assignAxisAtoms(atom);
777 }
778
779
780 if (!updateBondedTerms) {
781 return;
782 }
783
784
785 for (Bond bond : residue.getBondList()) {
786 AtomType a1 = bond.getAtom(0).getAtomType();
787 AtomType a2 = bond.getAtom(1).getAtomType();
788 BondType bondType = forceField.getBondType(a1, a2);
789 if (bondType == null) {
790 bondType = zeroBondType;
791 }
792 bond.setBondType(bondType);
793 }
794
795
796 for (Angle angle : residue.getAngleList()) {
797 AtomType a1 = angle.getAtom(0).getAtomType();
798 AtomType a2 = angle.getAtom(1).getAtomType();
799 AtomType a3 = angle.getAtom(2).getAtomType();
800 AngleType angleType = forceField.getAngleType(a1, a2, a3);
801 if (angleType == null) {
802 angleType = zeroAngleType;
803 }
804 angle.setAngleType(angleType);
805 }
806
807
808 for (StretchBend stretchBend : residue.getStretchBendList()) {
809 AtomType a1 = stretchBend.getAtom(0).getAtomType();
810 AtomType a2 = stretchBend.getAtom(1).getAtomType();
811 AtomType a3 = stretchBend.getAtom(2).getAtomType();
812 StretchBendType stretchBendType = forceField.getStretchBendType(a1, a2, a3);
813 if (stretchBendType == null) {
814 stretchBendType = zeroStretchBendType;
815 }
816 stretchBend.setStretchBendType(stretchBendType);
817 }
818
819
820 for (OutOfPlaneBend outOfPlaneBend : residue.getOutOfPlaneBendList()) {
821 AtomType a4 = outOfPlaneBend.getFourthAtom().getAtomType();
822 AtomType a0 = outOfPlaneBend.getFirstAngleAtom().getAtomType();
823 AtomType a1 = outOfPlaneBend.getTrigonalAtom().getAtomType();
824 AtomType a2 = outOfPlaneBend.getLastAngleAtom().getAtomType();
825 OutOfPlaneBendType outOfPlaneBendType = forceField.getOutOfPlaneBendType(a4, a0, a1, a2);
826 if (outOfPlaneBendType == null) {
827 outOfPlaneBendType = zeroOutOfPlaneBendType;
828 }
829 outOfPlaneBend.setOutOfPlaneBendType(outOfPlaneBendType);
830 }
831
832
833 for (Torsion torsion : residue.getTorsionList()) {
834 AtomType a1 = torsion.getAtom(0).getAtomType();
835 AtomType a2 = torsion.getAtom(1).getAtomType();
836 AtomType a3 = torsion.getAtom(2).getAtomType();
837 AtomType a4 = torsion.getAtom(3).getAtomType();
838 TorsionType torsionType = forceField.getTorsionType(a1, a2, a3, a4);
839 if (torsionType == null) {
840 torsionType = zeroTorsionType;
841 }
842 torsion.setTorsionType(torsionType);
843 }
844
845
846 for (PiOrbitalTorsion piOrbitalTorsion : residue.getPiOrbitalTorsionList()) {
847 Bond middleBond = piOrbitalTorsion.getMiddleBond();
848 AtomType a1 = middleBond.getAtom(0).getAtomType();
849 AtomType a2 = middleBond.getAtom(1).getAtomType();
850 PiOrbitalTorsionType piOrbitalTorsionType = forceField.getPiOrbitalTorsionType(a1, a2);
851 if (piOrbitalTorsionType == null) {
852 piOrbitalTorsionType = zeroPiOrbitalTorsionType;
853 }
854 piOrbitalTorsion.setPiOrbitalTorsionType(piOrbitalTorsionType);
855 }
856
857
858 List<ImproperTorsion> improperTorsions = residue.getImproperTorsionList();
859 if (improperTorsions != null && !improperTorsions.isEmpty()) {
860 logger.severe(
861 " Improper torsions are not supported yet for pH-dependent rotamer optimization.");
862 }
863
864 List<StretchTorsion> stretchTorsions = residue.getStretchTorsionList();
865 if (stretchTorsions != null && !stretchTorsions.isEmpty()) {
866 logger.severe(
867 " Stretch-torsions are not supported yet for pH-dependent rotamer optimization.");
868 }
869
870 List<AngleTorsion> angleTorsions = residue.getAngleTorsionList();
871 if (angleTorsions != null && !angleTorsions.isEmpty()) {
872 logger.severe(" Angle-torsions are not supported yet for pH-dependent rotamer optimization.");
873 }
874
875 List<TorsionTorsion> torsionTorsions = residue.getTorsionTorsionList();
876 if (torsionTorsions != null && !torsionTorsions.isEmpty()) {
877 logger.severe(
878 " Torsion-torsions are not supported yet for pH-dependent rotamer optimization.");
879 }
880
881 List<UreyBradley> ureyBradleys = residue.getUreyBradleyList();
882 if (ureyBradleys != null && !ureyBradleys.isEmpty()) {
883 logger.severe(" Urey-Bradleys are not supported yet for pH-dependent rotamer optimization.");
884 }
885
886 }
887
888 public double[] getMultipole(Atom atom, double titrationLambda, double tautomerLambda,
889 double[] multipole) {
890
891
892
893
894
895 AminoAcid3 aminoAcid3;
896 try {
897 aminoAcid3 = atom.getMSNode(Residue.class).getAminoAcid3();
898 } catch (Exception exception) {
899 return multipole;
900 }
901 String atomName = atom.getName();
902
903 switch (aminoAcid3) {
904 case LYS:
905 int atomIndex = LysineAtomNames.valueOf(atomName).ordinal();
906 MultipoleType lysM = lysMultipoleTypes[atomIndex][LysStates.LYS.ordinal()];
907 MultipoleType lydM = lysMultipoleTypes[atomIndex][LysStates.LYD.ordinal()];
908 double[] lys = lysM.getMultipole();
909 double[] lyd = lydM.getMultipole();
910 for (int i = 0; i < multipole.length; i++) {
911 multipole[i] = titrationLambda * lys[i] + (1.0 - titrationLambda) * lyd[i];
912 }
913 break;
914 case CYS:
915 atomIndex = CysteineAtomNames.valueOf(atomName).ordinal();
916 MultipoleType cysM = cysMultipoleTypes[atomIndex][CysStates.CYS.ordinal()];
917 MultipoleType cydM = cysMultipoleTypes[atomIndex][CysStates.CYD.ordinal()];
918 double[] cys = cysM.getMultipole();
919 double[] cyd = cydM.getMultipole();
920 for (int i = 0; i < multipole.length; i++) {
921 multipole[i] = titrationLambda * cys[i] + (1.0 - titrationLambda) * cyd[i];
922 }
923 break;
924 case HIS:
925 atomIndex = HistidineAtomNames.valueOf(atomName).ordinal();
926 MultipoleType hisM = hisMultipoleTypes[atomIndex][HisStates.HIS.ordinal()];
927 MultipoleType hidM = hisMultipoleTypes[atomIndex][HisStates.HID.ordinal()];
928 MultipoleType hieM = hisMultipoleTypes[atomIndex][HisStates.HIE.ordinal()];
929 double[] his = hisM.getMultipole();
930 double[] hid = hidM.getMultipole();
931 double[] hie = hieM.getMultipole();
932 for (int i = 0; i < multipole.length; i++) {
933 multipole[i] =
934 titrationLambda * his[i] + (1.0 - titrationLambda) * (tautomerLambda * hie[i]
935 + (1 - tautomerLambda) * hid[i]);
936 }
937 break;
938 case ASD:
939 atomIndex = AspartateAtomNames.valueOf(atomName).ordinal();
940 MultipoleType aspM = aspMultipoleTypes[atomIndex][AspStates.ASP.ordinal()];
941 MultipoleType ash1M = aspMultipoleTypes[atomIndex][AspStates.ASH1.ordinal()];
942 MultipoleType ash2M = aspMultipoleTypes[atomIndex][AspStates.ASH2.ordinal()];
943 double[] asp = aspM.getMultipole();
944 double[] ash1 = ash1M.getMultipole();
945 double[] ash2 = ash2M.getMultipole();
946 for (int i = 0; i < multipole.length; i++) {
947 multipole[i] =
948 titrationLambda * (tautomerLambda * ash1[i] + (1 - tautomerLambda) * ash2[i])
949 + (1.0 - titrationLambda) * asp[i];
950 }
951 break;
952 case GLD:
953 atomIndex = GlutamateAtomNames.valueOf(atomName).ordinal();
954 MultipoleType gluM = gluMultipoleTypes[atomIndex][GluStates.GLU.ordinal()];
955 MultipoleType glh1M = gluMultipoleTypes[atomIndex][GluStates.GLH1.ordinal()];
956 MultipoleType glh2M = gluMultipoleTypes[atomIndex][GluStates.GLH2.ordinal()];
957 double[] glu = gluM.getMultipole();
958 double[] glh1 = glh1M.getMultipole();
959 double[] glh2 = glh2M.getMultipole();
960 for (int i = 0; i < multipole.length; i++) {
961 multipole[i] =
962 titrationLambda * (tautomerLambda * glh1[i] + (1 - tautomerLambda) * glh2[i])
963 + (1.0 - titrationLambda) * glu[i];
964 }
965 break;
966 default:
967 return multipole;
968 }
969 return multipole;
970 }
971
972 public double[] getMultipoleTitrationDeriv(Atom atom, double titrationLambda,
973 double tautomerLambda, double[] multipole) {
974 AminoAcid3 aminoAcid3;
975 try {
976 aminoAcid3 = atom.getMSNode(Residue.class).getAminoAcid3();
977 } catch (Exception exception) {
978 return multipole;
979 }
980 String atomName = atom.getName();
981 switch (aminoAcid3) {
982 case LYS:
983 int atomIndex = LysineAtomNames.valueOf(atomName).ordinal();
984 double[] lys = lysMultipoleTypes[atomIndex][LysStates.LYS.ordinal()].getMultipole();
985 double[] lyd = lysMultipoleTypes[atomIndex][LysStates.LYD.ordinal()].getMultipole();
986 for (int i = 0; i < multipole.length; i++) {
987 multipole[i] = lys[i] - lyd[i];
988 }
989 break;
990 case CYS:
991 atomIndex = CysteineAtomNames.valueOf(atomName).ordinal();
992 double[] cys = cysMultipoleTypes[atomIndex][CysStates.CYS.ordinal()].getMultipole();
993 double[] cyd = cysMultipoleTypes[atomIndex][CysStates.CYD.ordinal()].getMultipole();
994 for (int i = 0; i < multipole.length; i++) {
995 multipole[i] = cys[i] - cyd[i];
996 }
997 break;
998 case HIS:
999 atomIndex = HistidineAtomNames.valueOf(atomName).ordinal();
1000 double[] his = hisMultipoleTypes[atomIndex][HisStates.HIS.ordinal()].getMultipole();
1001 double[] hid = hisMultipoleTypes[atomIndex][HisStates.HID.ordinal()].getMultipole();
1002 double[] hie = hisMultipoleTypes[atomIndex][HisStates.HIE.ordinal()].getMultipole();
1003 for (int i = 0; i < multipole.length; i++) {
1004 multipole[i] = his[i] - (tautomerLambda * hie[i] + (1 - tautomerLambda) * hid[i]);
1005 }
1006 break;
1007 case ASD:
1008 atomIndex = AspartateAtomNames.valueOf(atomName).ordinal();
1009 double[] asp = aspMultipoleTypes[atomIndex][AspStates.ASP.ordinal()].getMultipole();
1010 double[] ash1 = aspMultipoleTypes[atomIndex][AspStates.ASH1.ordinal()].getMultipole();
1011 double[] ash2 = aspMultipoleTypes[atomIndex][AspStates.ASH2.ordinal()].getMultipole();
1012 for (int i = 0; i < multipole.length; i++) {
1013 multipole[i] = (tautomerLambda * ash1[i] + (1 - tautomerLambda) * ash2[i]) - asp[i];
1014 }
1015 break;
1016 case GLD:
1017 atomIndex = GlutamateAtomNames.valueOf(atomName).ordinal();
1018 double[] glu = gluMultipoleTypes[atomIndex][GluStates.GLU.ordinal()].getMultipole();
1019 double[] glh1 = gluMultipoleTypes[atomIndex][GluStates.GLH1.ordinal()].getMultipole();
1020 double[] glh2 = gluMultipoleTypes[atomIndex][GluStates.GLH2.ordinal()].getMultipole();
1021 for (int i = 0; i < multipole.length; i++) {
1022 multipole[i] = (tautomerLambda * glh1[i] + (1 - tautomerLambda) * glh2[i]) - glu[i];
1023 }
1024 break;
1025 default:
1026 return multipole;
1027 }
1028 return multipole;
1029 }
1030
1031 public double[] getMultipoleTautomerDeriv(Atom atom, double titrationLambda, double tautomerLambda,
1032 double[] multipole) {
1033 AminoAcid3 aminoAcid3;
1034 try {
1035 aminoAcid3 = atom.getMSNode(Residue.class).getAminoAcid3();
1036 } catch (Exception exception) {
1037 return multipole;
1038 }
1039 String atomName = atom.getName();
1040 switch (aminoAcid3) {
1041 case HIS:
1042 int atomIndex = HistidineAtomNames.valueOf(atomName).ordinal();
1043 double[] his = hisMultipoleTypes[atomIndex][HisStates.HIS.ordinal()].getMultipole();
1044 double[] hid = hisMultipoleTypes[atomIndex][HisStates.HID.ordinal()].getMultipole();
1045 double[] hie = hisMultipoleTypes[atomIndex][HisStates.HIE.ordinal()].getMultipole();
1046 for (int i = 0; i < multipole.length; i++) {
1047 multipole[i] = (1.0 - titrationLambda) * (hie[i] - hid[i]);
1048 }
1049 break;
1050 case ASD:
1051 atomIndex = AspartateAtomNames.valueOf(atomName).ordinal();
1052 double[] asp = aspMultipoleTypes[atomIndex][AspStates.ASP.ordinal()].getMultipole();
1053 double[] ash1 = aspMultipoleTypes[atomIndex][AspStates.ASH1.ordinal()].getMultipole();
1054 double[] ash2 = aspMultipoleTypes[atomIndex][AspStates.ASH2.ordinal()].getMultipole();
1055 for (int i = 0; i < multipole.length; i++) {
1056 multipole[i] = titrationLambda * (ash1[i] - ash2[i]);
1057 }
1058 break;
1059 case GLD:
1060 atomIndex = GlutamateAtomNames.valueOf(atomName).ordinal();
1061 double[] glu = gluMultipoleTypes[atomIndex][GluStates.GLU.ordinal()].getMultipole();
1062 double[] glh1 = gluMultipoleTypes[atomIndex][GluStates.GLH1.ordinal()].getMultipole();
1063 double[] glh2 = gluMultipoleTypes[atomIndex][GluStates.GLH2.ordinal()].getMultipole();
1064 for (int i = 0; i < multipole.length; i++) {
1065 multipole[i] = titrationLambda * (glh1[i] - glh2[i]);
1066 }
1067 break;
1068 case LYS:
1069 case CYS:
1070 default:
1071 return multipole;
1072 }
1073 return multipole;
1074 }
1075
1076 public double getPolarizability(Atom atom, double titrationLambda, double tautomerLambda,
1077 double defaultPolarizability) {
1078 AminoAcid3 aminoAcid3;
1079 try {
1080 aminoAcid3 = atom.getMSNode(Residue.class).getAminoAcid3();
1081 } catch (Exception exception) {
1082 return defaultPolarizability;
1083 }
1084 String atomName = atom.getName();
1085 switch (aminoAcid3) {
1086 case LYS:
1087 int atomIndex = LysineAtomNames.valueOf(atomName).ordinal();
1088 double lys = lysPolarizeTypes[atomIndex][LysStates.LYS.ordinal()].polarizability;
1089 double lyd = lysPolarizeTypes[atomIndex][LysStates.LYD.ordinal()].polarizability;
1090 return titrationLambda * lys + (1.0 - titrationLambda) * lyd;
1091 case CYS:
1092 atomIndex = CysteineAtomNames.valueOf(atomName).ordinal();
1093 double cys = cysPolarizeTypes[atomIndex][CysStates.CYS.ordinal()].polarizability;
1094 double cyd = cysPolarizeTypes[atomIndex][CysStates.CYD.ordinal()].polarizability;
1095 return titrationLambda * cys + (1.0 - titrationLambda) * cyd;
1096 case HIS:
1097 atomIndex = HistidineAtomNames.valueOf(atomName).ordinal();
1098 double his = hisPolarizeTypes[atomIndex][HisStates.HIS.ordinal()].polarizability;
1099 double hid = hisPolarizeTypes[atomIndex][HisStates.HID.ordinal()].polarizability;
1100 double hie = hisPolarizeTypes[atomIndex][HisStates.HIE.ordinal()].polarizability;
1101 return titrationLambda * his + (1.0 - titrationLambda) * (tautomerLambda * hie
1102 + (1.0 - tautomerLambda) * hid);
1103 case ASD:
1104 atomIndex = AspartateAtomNames.valueOf(atomName).ordinal();
1105 double asp = aspPolarizeTypes[atomIndex][AspStates.ASP.ordinal()].polarizability;
1106 double ash1 = aspPolarizeTypes[atomIndex][AspStates.ASH1.ordinal()].polarizability;
1107 double ash2 = aspPolarizeTypes[atomIndex][AspStates.ASH2.ordinal()].polarizability;
1108 return titrationLambda * (tautomerLambda * ash1 + (1.0 - tautomerLambda) * ash2)
1109 + (1.0 - titrationLambda) * asp;
1110 case GLD:
1111 atomIndex = GlutamateAtomNames.valueOf(atomName).ordinal();
1112 double glu = gluPolarizeTypes[atomIndex][GluStates.GLU.ordinal()].polarizability;
1113 double glh1 = gluPolarizeTypes[atomIndex][GluStates.GLH1.ordinal()].polarizability;
1114 double glh2 = gluPolarizeTypes[atomIndex][GluStates.GLH2.ordinal()].polarizability;
1115 return titrationLambda * (tautomerLambda * glh1 + (1.0 - tautomerLambda) * glh2)
1116 + (1.0 - titrationLambda) * glu;
1117 default:
1118 return defaultPolarizability;
1119 }
1120 }
1121
1122 public double getPolarizabilityTitrationDeriv(Atom atom, double titrationLambda,
1123 double tautomerLambda) {
1124 AminoAcid3 aminoAcid3;
1125 try {
1126 aminoAcid3 = atom.getMSNode(Residue.class).getAminoAcid3();
1127 } catch (Exception exception) {
1128 return 0.0;
1129 }
1130 String atomName = atom.getName();
1131 switch (aminoAcid3) {
1132 case LYS:
1133 int atomIndex = LysineAtomNames.valueOf(atomName).ordinal();
1134 double lys = lysPolarizeTypes[atomIndex][LysStates.LYS.ordinal()].polarizability;
1135 double lyd = lysPolarizeTypes[atomIndex][LysStates.LYD.ordinal()].polarizability;
1136 return lys - lyd;
1137 case CYS:
1138 atomIndex = CysteineAtomNames.valueOf(atomName).ordinal();
1139 double cys = cysPolarizeTypes[atomIndex][CysStates.CYS.ordinal()].polarizability;
1140 double cyd = cysPolarizeTypes[atomIndex][CysStates.CYD.ordinal()].polarizability;
1141 return cys - cyd;
1142 case HIS:
1143 atomIndex = HistidineAtomNames.valueOf(atomName).ordinal();
1144 double his = hisPolarizeTypes[atomIndex][HisStates.HIS.ordinal()].polarizability;
1145 double hid = hisPolarizeTypes[atomIndex][HisStates.HID.ordinal()].polarizability;
1146 double hie = hisPolarizeTypes[atomIndex][HisStates.HIE.ordinal()].polarizability;
1147 return his - (tautomerLambda * hie + (1.0 - tautomerLambda) * hid);
1148 case ASD:
1149 atomIndex = AspartateAtomNames.valueOf(atomName).ordinal();
1150 double asp = aspPolarizeTypes[atomIndex][AspStates.ASP.ordinal()].polarizability;
1151 double ash1 = aspPolarizeTypes[atomIndex][AspStates.ASH1.ordinal()].polarizability;
1152 double ash2 = aspPolarizeTypes[atomIndex][AspStates.ASH2.ordinal()].polarizability;
1153 return (tautomerLambda * ash1 + (1.0 - tautomerLambda) * ash2) - asp;
1154 case GLD:
1155 atomIndex = GlutamateAtomNames.valueOf(atomName).ordinal();
1156 double glu = gluPolarizeTypes[atomIndex][GluStates.GLU.ordinal()].polarizability;
1157 double glh1 = gluPolarizeTypes[atomIndex][GluStates.GLH1.ordinal()].polarizability;
1158 double glh2 = gluPolarizeTypes[atomIndex][GluStates.GLH2.ordinal()].polarizability;
1159 return (tautomerLambda * glh1 + (1.0 - tautomerLambda) * glh2) - glu;
1160 default:
1161 return 0.0;
1162 }
1163 }
1164
1165 public double getPolarizabilityTautomerDeriv(Atom atom, double titrationLambda,
1166 double tautomerLambda) {
1167 AminoAcid3 aminoAcid3;
1168 try {
1169 aminoAcid3 = atom.getMSNode(Residue.class).getAminoAcid3();
1170 } catch (Exception exception) {
1171 return 0.0;
1172 }
1173 String atomName = atom.getName();
1174 switch (aminoAcid3) {
1175 case HIS:
1176 int atomIndex = HistidineAtomNames.valueOf(atomName).ordinal();
1177 double his = hisPolarizeTypes[atomIndex][HisStates.HIS.ordinal()].polarizability;
1178 double hid = hisPolarizeTypes[atomIndex][HisStates.HID.ordinal()].polarizability;
1179 double hie = hisPolarizeTypes[atomIndex][HisStates.HIE.ordinal()].polarizability;
1180 return (1.0 - titrationLambda) * (hie - hid);
1181 case ASD:
1182 atomIndex = AspartateAtomNames.valueOf(atomName).ordinal();
1183 double asp = aspPolarizeTypes[atomIndex][AspStates.ASP.ordinal()].polarizability;
1184 double ash1 = aspPolarizeTypes[atomIndex][AspStates.ASH1.ordinal()].polarizability;
1185 double ash2 = aspPolarizeTypes[atomIndex][AspStates.ASH2.ordinal()].polarizability;
1186 return titrationLambda * (ash1 - ash2);
1187 case GLD:
1188 atomIndex = GlutamateAtomNames.valueOf(atomName).ordinal();
1189 double glu = gluPolarizeTypes[atomIndex][GluStates.GLU.ordinal()].polarizability;
1190 double glh1 = gluPolarizeTypes[atomIndex][GluStates.GLH1.ordinal()].polarizability;
1191 double glh2 = gluPolarizeTypes[atomIndex][GluStates.GLH2.ordinal()].polarizability;
1192 return titrationLambda * (glh1 - glh2);
1193 case LYS:
1194 case CYS:
1195 default:
1196 return 0.0;
1197 }
1198 }
1199
1200 public static boolean isTitratingHydrogen(AminoAcid3 aminoAcid3, Atom atom) {
1201 boolean isTitratingHydrogen = false;
1202 String atomName = atom.getName();
1203 switch (aminoAcid3) {
1204 case ASD -> {
1205 if (atomName.equals(AspartateAtomNames.HD1.name()) || atomName.equals(
1206 AspartateAtomNames.HD2.name())) {
1207 isTitratingHydrogen = true;
1208 }
1209 }
1210 case GLD -> {
1211 if (atomName.equals(GlutamateAtomNames.HE1.name()) || atomName.equals(
1212 GlutamateAtomNames.HE2.name())) {
1213 isTitratingHydrogen = true;
1214 }
1215 }
1216 case HIS -> {
1217 if (atomName.equals(HistidineAtomNames.HD1.name()) || atomName.equals(
1218 HistidineAtomNames.HE2.name())) {
1219 isTitratingHydrogen = true;
1220 }
1221 }
1222 case LYS -> {
1223 if (atomName.equals(LysineAtomNames.HZ3.name())) {
1224 isTitratingHydrogen = true;
1225 }
1226 }
1227 case CYS -> {
1228 if (atomName.equals(CysteineAtomNames.HG.name())) {
1229 isTitratingHydrogen = true;
1230 }
1231 }
1232 }
1233 return isTitratingHydrogen;
1234 }
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245 public static boolean isTitratingHeavy(AminoAcid3 aminoAcid3, Atom atom) {
1246 boolean isTitratingHeavy = false;
1247 String atomName = atom.getName();
1248 switch (aminoAcid3) {
1249 case ASD -> {
1250 if (atomName.equals(AspartateAtomNames.OD1.name()) || atomName.equals(
1251 AspartateAtomNames.OD2.name())) {
1252 isTitratingHeavy = true;
1253 }
1254 }
1255 case GLD -> {
1256 if (atomName.equals(GlutamateAtomNames.OE1.name()) || atomName.equals(
1257 GlutamateAtomNames.OE2.name())) {
1258 isTitratingHeavy = true;
1259 }
1260 }
1261 case CYS -> {
1262 if (atomName.equals(CysteineAtomNames.SG.name())) {
1263 isTitratingHeavy = true;
1264 }
1265 }
1266 }
1267 return isTitratingHeavy;
1268 }
1269
1270 public static int getTitratingHydrogenDirection(AminoAcid3 aminoAcid3, Atom atom) {
1271 int tautomerDirection = 0;
1272 String atomName = atom.getName();
1273 switch (aminoAcid3) {
1274 case ASD -> {
1275 if (atomName.equals(AspartateAtomNames.HD1.name())) {
1276 tautomerDirection = AspartateAtomNames.HD1.tautomerDirection;
1277 } else if (atomName.equals(AspartateAtomNames.HD2.name())) {
1278 tautomerDirection = AspartateAtomNames.HD2.tautomerDirection;
1279 }
1280 }
1281 case GLD -> {
1282 if (atomName.equals(GlutamateAtomNames.HE1.name())) {
1283 tautomerDirection = GlutamateAtomNames.HE1.tautomerDirection;
1284 } else if (atomName.equals(GlutamateAtomNames.HE2.name())) {
1285 tautomerDirection = GlutamateAtomNames.HE2.tautomerDirection;
1286 }
1287 }
1288 case HIS -> {
1289 if (atomName.equals(HistidineAtomNames.HD1.name())) {
1290 tautomerDirection = HistidineAtomNames.HD1.tautomerDirection;
1291 } else if (atomName.equals(HistidineAtomNames.HE2.name())) {
1292 tautomerDirection = HistidineAtomNames.HE2.tautomerDirection;
1293 }
1294 }
1295 }
1296 return tautomerDirection;
1297 }
1298
1299 private void constructHISState(int biotypeCB, HisStates hisState) {
1300 int state = hisState.ordinal();
1301 for (HistidineAtomNames atomName : HistidineAtomNames.values()) {
1302 int index = atomName.ordinal();
1303 int offset = atomName.getOffsetHIS(hisState);
1304 if (offset < 0) {
1305 hisAtomTypes[index][state] = dummyHydrogenAtomType;
1306
1307 if (hisState == HisStates.HID) {
1308 hisMultipoleTypes[index][state] = hidZeroMultipoleType;
1309 } else if (hisState == HisStates.HIE) {
1310 hisMultipoleTypes[index][state] = hieZeroMultipoleType;
1311 } else {
1312 logger.severe(" Error constructing HIS states.");
1313 }
1314 hisPolarizeTypes[index][state] = zeroPolarizeType;
1315 hisVDWTypes[index][state] = forceField.getVDWType(Integer.toString(0));
1316 hisSoluteTypes[index][state] = zeroSoluteType;
1317 } else {
1318 int biotype = biotypeCB + offset;
1319 hisAtomTypes[index][state] = findAtomType(biotype, forceField);
1320 String key = hisAtomTypes[index][state].getKey();
1321 hisMultipoleTypes[index][state] = forceField.getMultipoleTypeBeginsWith(key);
1322 hisPolarizeTypes[index][state] = forceField.getPolarizeType(key);
1323 int atomClass = hisAtomTypes[index][state].atomClass;
1324 hisVDWTypes[index][state] = forceField.getVDWType("" + atomClass);
1325 hisSoluteTypes[index][state] = getSoluteType(forceField, hisAtomTypes[index][state],
1326 hisVDWTypes[index][state]);
1327 if (hisMultipoleTypes[index][state] == null || hisPolarizeTypes[index][state] == null
1328 || hisSoluteTypes[index][state] == null) {
1329 logger.severe(format(" Titration parameters could not be assigned for His atom %s.\n %s\n",
1330 atomName, hisAtomTypes[index][state]));
1331 }
1332 }
1333 }
1334 }
1335
1336 private void constructLYSState(int biotypeCB, LysStates lysState) {
1337 int state = lysState.ordinal();
1338 for (LysineAtomNames atomName : LysineAtomNames.values()) {
1339 int index = atomName.ordinal();
1340 int offset = atomName.getOffsetLYS(lysState);
1341 if (offset < 0) {
1342
1343 lysAtomTypes[index][state] = dummyHydrogenAtomType;
1344
1345 lysMultipoleTypes[index][state] = lydZeroMultipoleType;
1346 lysPolarizeTypes[index][state] = zeroPolarizeType;
1347 lysVDWTypes[index][state] = forceField.getVDWType(Integer.toString(0));
1348 lysSoluteTypes[index][state] = zeroSoluteType;
1349 } else {
1350 int biotype = biotypeCB + offset;
1351 lysAtomTypes[index][state] = findAtomType(biotype, forceField);
1352 String key = lysAtomTypes[index][state].getKey();
1353 lysMultipoleTypes[index][state] = forceField.getMultipoleTypeBeginsWith(key);
1354 lysPolarizeTypes[index][state] = forceField.getPolarizeType(key);
1355 int atomClass = lysAtomTypes[index][state].atomClass;
1356 lysVDWTypes[index][state] = forceField.getVDWType("" + atomClass);
1357 lysSoluteTypes[index][state] = getSoluteType(forceField, lysAtomTypes[index][state],
1358 lysVDWTypes[index][state]);
1359 if (lysMultipoleTypes[index][state] == null || lysPolarizeTypes[index][state] == null
1360 || lysSoluteTypes[index][state] == null) {
1361 logger.severe(
1362 format(" Titration parameters could not be assigned for Lys atom %s.\n %s\n", atomName,
1363 lysAtomTypes[index][state]));
1364 }
1365 }
1366 }
1367 }
1368
1369 private void constructASPState(int biotypeCB, AspStates aspState) {
1370 int state = aspState.ordinal();
1371 for (AspartateAtomNames atomName : AspartateAtomNames.values()) {
1372 int index = atomName.ordinal();
1373 int offset = atomName.getOffset(aspState);
1374 if (offset < 0) {
1375
1376 aspAtomTypes[index][state] = dummyHydrogenAtomType;
1377
1378 if (aspState == AspStates.ASP) {
1379 aspMultipoleTypes[index][state] = aspZeroMultipoleType;
1380 } else {
1381 aspMultipoleTypes[index][state] = ashZeroMultipoleType;
1382 }
1383 aspPolarizeTypes[index][state] = zeroPolarizeType;
1384 aspVDWTypes[index][state] = forceField.getVDWType(Integer.toString(0));
1385 aspSoluteTypes[index][state] = zeroSoluteType;
1386 } else {
1387 int biotype = biotypeCB + offset;
1388 aspAtomTypes[index][state] = findAtomType(biotype, forceField);
1389 String key = aspAtomTypes[index][state].getKey();
1390 aspMultipoleTypes[index][state] = forceField.getMultipoleTypeBeginsWith(key);
1391 aspPolarizeTypes[index][state] = forceField.getPolarizeType(key);
1392 int atomClass = aspAtomTypes[index][state].atomClass;
1393 aspVDWTypes[index][state] = forceField.getVDWType("" + atomClass);
1394 aspSoluteTypes[index][state] = getSoluteType(forceField, aspAtomTypes[index][state],
1395 aspVDWTypes[index][state]);
1396 if (aspMultipoleTypes[index][state] == null || aspPolarizeTypes[index][state] == null
1397 || aspSoluteTypes[index][state] == null) {
1398 logger.severe(
1399 format(" Titration parameters could not be assigned for Asp atom %s.\n %s\n", atomName,
1400 aspAtomTypes[index][state]));
1401 }
1402 }
1403 }
1404 }
1405
1406 private void constructGLUState(int biotypeCB, GluStates gluState) {
1407 int state = gluState.ordinal();
1408 for (GlutamateAtomNames atomName : GlutamateAtomNames.values()) {
1409 int index = atomName.ordinal();
1410 int offset = atomName.getOffset(gluState);
1411 if (offset < 0) {
1412
1413 gluAtomTypes[index][state] = dummyHydrogenAtomType;
1414
1415 if (gluState == GluStates.GLU) {
1416 gluMultipoleTypes[index][state] = gluZeroMultipoleType;
1417 } else {
1418 gluMultipoleTypes[index][state] = glhZeroMultipoleType;
1419 }
1420 gluPolarizeTypes[index][state] = zeroPolarizeType;
1421 gluVDWTypes[index][state] = forceField.getVDWType(Integer.toString(0));
1422 gluSoluteTypes[index][state] = zeroSoluteType;
1423 } else {
1424 int biotype = biotypeCB + offset;
1425 gluAtomTypes[index][state] = findAtomType(biotype, forceField);
1426 String key = gluAtomTypes[index][state].getKey();
1427 gluMultipoleTypes[index][state] = forceField.getMultipoleTypeBeginsWith(key);
1428 gluPolarizeTypes[index][state] = forceField.getPolarizeType(key);
1429 int atomClass = gluAtomTypes[index][state].atomClass;
1430 gluVDWTypes[index][state] = forceField.getVDWType("" + atomClass);
1431 gluSoluteTypes[index][state] = getSoluteType(forceField, gluAtomTypes[index][state],
1432 gluVDWTypes[index][state]);
1433 if (gluMultipoleTypes[index][state] == null || gluPolarizeTypes[index][state] == null
1434 || gluSoluteTypes[index][state] == null) {
1435 logger.severe(
1436 format(" Titration parameters could not be assigned for Glu atom %s.\n %s\n", atomName,
1437 gluAtomTypes[index][state]));
1438 }
1439 }
1440 }
1441 }
1442
1443 private void constructCYSState(int biotypeCB, CysStates cysState) {
1444 int state = cysState.ordinal();
1445 for (CysteineAtomNames atomName : CysteineAtomNames.values()) {
1446 int index = atomName.ordinal();
1447 int offset = atomName.getOffsetCYS(cysState);
1448 if (offset < 0) {
1449
1450 cysAtomTypes[index][state] = dummyHydrogenAtomType;
1451
1452 cysMultipoleTypes[index][state] = cydZeroMultipoleType;
1453 cysPolarizeTypes[index][state] = zeroPolarizeType;
1454 cysVDWTypes[index][state] = forceField.getVDWType(Integer.toString(0));
1455 cysSoluteTypes[index][state] = zeroSoluteType;
1456 } else {
1457 int biotype = biotypeCB + offset;
1458 cysAtomTypes[index][state] = findAtomType(biotype, forceField);
1459 String key = cysAtomTypes[index][state].getKey();
1460 cysMultipoleTypes[index][state] = forceField.getMultipoleTypeBeginsWith(key);
1461
1462 if (cysMultipoleTypes[index][state] == null) {
1463 if (cysState == CysStates.CYS) {
1464 if (atomName == CysteineAtomNames.CB) {
1465 cysMultipoleTypes[index][state] = forceField.getMultipoleType(key + " 8 45");
1466 } else {
1467
1468 cysMultipoleTypes[index][state] = forceField.getMultipoleType(key + " 43 8");
1469 }
1470 } else {
1471 if (atomName == CysteineAtomNames.CB) {
1472 cysMultipoleTypes[index][state] = forceField.getMultipoleType(key + " 8 49");
1473 } else {
1474
1475 cysMultipoleTypes[index][state] = forceField.getMultipoleType(key + " 43 8");
1476 }
1477 }
1478 }
1479 cysPolarizeTypes[index][state] = forceField.getPolarizeType(key);
1480 int atomClass = cysAtomTypes[index][state].atomClass;
1481 cysVDWTypes[index][state] = forceField.getVDWType("" + atomClass);
1482 cysSoluteTypes[index][state] = getSoluteType(forceField, cysAtomTypes[index][state],
1483 cysVDWTypes[index][state]);
1484 if (cysMultipoleTypes[index][state] == null || cysPolarizeTypes[index][state] == null
1485 || cysSoluteTypes[index][state] == null) {
1486 logger.severe(
1487 format(" Titration parameters could not be assigned for Cys atom %s.\n %s\n", atomName,
1488 cysAtomTypes[index][state]));
1489 }
1490 }
1491 }
1492 }
1493
1494 private void checkParameterTypes(String label, AtomType[][] atomTypes,
1495 PolarizeType[][] polarizeTypes, MultipoleType[][] multipoleTypes, VDWType[][] vdwTypes) {
1496 int states = multipoleTypes.length;
1497 int types = multipoleTypes[0].length;
1498 StringBuilder sb = new StringBuilder();
1499 for (int t = 0; t < types; t++) {
1500 MultipoleFrameDefinition frame0 = multipoleTypes[0][t].frameDefinition;
1501 double eps0 = vdwTypes[0][t].wellDepth;
1502 double rad0 = vdwTypes[0][t].radius;
1503 sb.append(format("\n %s Type %d\n", label, t));
1504 sb.append(format(" %s\n %s\n %s\n %s\n", atomTypes[0][t], polarizeTypes[0][t],
1505 multipoleTypes[0][t], vdwTypes[0][t]));
1506 for (int s = 1; s < states; s++) {
1507 sb.append(format(" %s\n %s\n %s\n %s\n", atomTypes[s][t], polarizeTypes[s][t],
1508 multipoleTypes[s][t], vdwTypes[s][t]));
1509 MultipoleFrameDefinition frame = multipoleTypes[s][t].frameDefinition;
1510
1511 if (!frame0.equals(frame)) {
1512 sb.append("\n Incompatible multipole frames:\n");
1513 sb.append(format(" %s\n %s\n %s\n", atomTypes[0][t], polarizeTypes[0][t],
1514 multipoleTypes[0][t]));
1515 sb.append(format(" %s\n %s\n %s\n", atomTypes[s][t], polarizeTypes[s][t],
1516 multipoleTypes[s][t]));
1517 }
1518
1519 if (atomTypes[0][t].atomicNumber != 1) {
1520 double epsS = vdwTypes[s][t].wellDepth;
1521 double radS = vdwTypes[s][t].radius;
1522 if (epsS != eps0 || radS != rad0) {
1523 sb.append("\n Incompatible vdW types:\n");
1524 sb.append(format(" %s\n %s\n", atomTypes[0][t], vdwTypes[0][t]));
1525 sb.append(format(" %s\n %s\n", atomTypes[s][t], vdwTypes[s][t]));
1526 }
1527 }
1528 }
1529 }
1530
1531 if (logger.isLoggable(Level.FINE)) {
1532 logger.fine(sb.toString());
1533 }
1534 }
1535
1536 private SoluteType getSoluteType(ForceField forceField, AtomType atomType, VDWType vdwType) {
1537 SoluteType soluteType = SoluteType.getCensusSoluteType(atomType.atomicNumber);
1538 switch (soluteRadiiType) {
1539 case SOLUTE:
1540 SoluteType type = SoluteType.getFitSoluteType(forceField, atomType.type);
1541 if (type != null) {
1542 soluteType = type;
1543 }
1544 break;
1545 case VDW:
1546 type = SoluteType.getVDWSoluteType(vdwType);
1547 if (type != null) {
1548 soluteType = type;
1549 }
1550 break;
1551 }
1552 if (soluteType == null) {
1553 logger.severe(
1554 format(" No solute type (%s) for %d:\n \"%s\"\n %s", soluteRadiiType, atomType.type,
1555 atomType, vdwType));
1556 }
1557 return soluteType;
1558 }
1559
1560 public void setRotamerPhBias(double temperature, double pH) {
1561
1562
1563
1564 rotamerPhBiasMap.put(ASH, 0.0);
1565
1566
1567
1568
1569 double acidostat = LOG10 * Constants.R * temperature * (Titration.ASHtoASP.pKa - pH);
1570 double fMod = Titration.ASHtoASP.freeEnergyDiff;
1571 if(tanhCorrection){
1572 fMod = Titration.ASHtoASP.freeEnergyDiffGK;
1573 if(proteinDielectric == 2.0){
1574 fMod = Titration.ASHtoASP.freeEnergyDiffGK2;
1575 }
1576 } else if(proteinDielectric == 2.0){
1577 fMod = Titration.ASHtoASP.freeEnergyDiff2;
1578 }
1579 rotamerPhBiasMap.put(ASP, acidostat - fMod);
1580
1581
1582
1583
1584
1585 rotamerPhBiasMap.put(GLH, 0.0);
1586
1587
1588
1589
1590 acidostat = LOG10 * Constants.R * temperature * (Titration.GLHtoGLU.pKa - pH);
1591 fMod = Titration.GLHtoGLU.freeEnergyDiff;
1592 if(tanhCorrection){
1593 fMod = Titration.GLHtoGLU.freeEnergyDiffGK;
1594 if(proteinDielectric == 2.0){
1595 fMod = Titration.GLHtoGLU.freeEnergyDiffGK2;
1596 }
1597 } else if(proteinDielectric == 2.0){
1598 fMod = Titration.GLHtoGLU.freeEnergyDiff2;
1599 }
1600 rotamerPhBiasMap.put(GLU, acidostat - fMod);
1601
1602
1603
1604
1605
1606 rotamerPhBiasMap.put(LYS, 0.0);
1607
1608
1609
1610
1611 acidostat = LOG10 * Constants.R * temperature * (Titration.LYStoLYD.pKa - pH);
1612 fMod = Titration.LYStoLYD.freeEnergyDiff;
1613 if(tanhCorrection){
1614 fMod = Titration.LYStoLYD.freeEnergyDiffGK;
1615 if(proteinDielectric == 2.0){
1616 fMod = Titration.LYStoLYD.freeEnergyDiffGK2;
1617 }
1618 } else if(proteinDielectric == 2.0){
1619 fMod = Titration.LYStoLYD.freeEnergyDiff2;
1620 }
1621 rotamerPhBiasMap.put(LYD, acidostat - fMod);
1622
1623
1624
1625
1626 rotamerPhBiasMap.put(CYS, 0.0);
1627
1628
1629
1630
1631 acidostat = LOG10 * Constants.R * temperature * (Titration.CYStoCYD.pKa - pH);
1632 fMod = Titration.CYStoCYD.freeEnergyDiff;
1633 if(tanhCorrection){
1634 fMod = Titration.CYStoCYD.freeEnergyDiffGK;
1635 if(proteinDielectric == 2.0){
1636 fMod = Titration.CYStoCYD.freeEnergyDiffGK2;
1637 }
1638 } else if(proteinDielectric == 2.0){
1639 fMod = Titration.CYStoCYD.freeEnergyDiff2;
1640 }
1641 rotamerPhBiasMap.put(CYD, acidostat - fMod);
1642
1643
1644
1645
1646 rotamerPhBiasMap.put(HIS, 0.0);
1647
1648
1649
1650
1651 acidostat = LOG10 * Constants.R * temperature * (Titration.HIStoHID.pKa - pH);
1652 fMod = Titration.HIStoHID.freeEnergyDiff;
1653 if(tanhCorrection){
1654 fMod = Titration.HIStoHID.freeEnergyDiffGK;
1655 if(proteinDielectric == 2.0){
1656 fMod = Titration.HIStoHID.freeEnergyDiffGK2;
1657 }
1658 } else if(proteinDielectric == 2.0){
1659 fMod = Titration.HIStoHID.freeEnergyDiff2;
1660 }
1661 rotamerPhBiasMap.put(HID, acidostat - fMod);
1662
1663
1664
1665
1666 acidostat = LOG10 * Constants.R * temperature * (Titration.HIStoHIE.pKa - pH);
1667 fMod = Titration.HIStoHIE.freeEnergyDiff;
1668 if(tanhCorrection){
1669 fMod = Titration.HIStoHIE.freeEnergyDiffGK;
1670 if(proteinDielectric == 2.0){
1671 fMod = Titration.HIStoHIE.freeEnergyDiffGK2;
1672 }
1673 } else if(proteinDielectric == 2.0){
1674 fMod = Titration.HIStoHIE.freeEnergyDiff2;
1675 }
1676 rotamerPhBiasMap.put(HIE, acidostat - fMod);
1677 }
1678
1679 public double getRotamerPhBias(AminoAcid3 AA3) {
1680 return rotamerPhBiasMap.getOrDefault(AA3, 0.0);
1681 }
1682
1683 public double getTotalRotamerPhBias(Rotamer[] rotamers) {
1684 double total = 0.0;
1685 for (Rotamer r : rotamers) {
1686 if (r.isTitrating) {
1687 total += getRotamerPhBias(r.aminoAcid3);
1688 }
1689 }
1690 return total;
1691 }
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702 public static double[] predictHillCoeffandPka(double[] pHScale, double[] residueFractions) {
1703
1704
1705 Potential hendersonHasselbach = new Potential() {
1706 static final double logb10 = Math.log(10);
1707
1708 @Override
1709 public double energy(double[] x) {
1710 return leastSquaresLoss(residueFractions, getValues(x));
1711 }
1712
1713 public double leastSquaresLoss(double[] residueFractions, double[] guessedFractions) {
1714 double loss = 0.0;
1715 for (int i = 0; i < residueFractions.length; i++) {
1716 loss += Math.pow(residueFractions[i] - guessedFractions[i], 2);
1717 }
1718 return loss;
1719 }
1720
1721 public double[] getValues(double[] x) {
1722 double[] values = new double[pHScale.length];
1723 for (int i = 0; i < pHScale.length; i++) {
1724 values[i] = 1 / (1 + Math.pow(10, x[0] * (x[1] - pHScale[i])));
1725 }
1726 return values;
1727 }
1728
1729 public void gradient(double[] x, double[] gradient) {
1730
1731 Arrays.fill(gradient, 0.0);
1732 double[] values = getValues(x);
1733 for (int i = 0; i < pHScale.length; i++) {
1734
1735 double term = Math.pow(10, x[0] * (x[1] - pHScale[i]));
1736
1737
1738 double d = (1 + term) * (1 + term);
1739
1740
1741 gradient[0] += 2*(residueFractions[i] - values[i]) * logb10 * (x[1] - pHScale[i]) * term / d;
1742
1743
1744 gradient[1] += 2*(residueFractions[i] - values[i]) * x[0] * logb10 * term / d;
1745 }
1746 }
1747
1748 @Override
1749 public double energyAndGradient(double[] x, double[] g) {
1750 gradient(x, g);
1751 return energy(x);
1752 }
1753
1754 @Override
1755 public double[] getAcceleration(double[] acceleration) {
1756 return new double[0];
1757 }
1758
1759 @Override
1760 public double[] getCoordinates(double[] parameters) {
1761 return new double[0];
1762 }
1763
1764 @Override
1765 public STATE getEnergyTermState() {
1766 return null;
1767 }
1768
1769 @Override
1770 public void setEnergyTermState(STATE state) {}
1771 @Override
1772 public double[] getMass() {
1773 return new double[0];
1774 }
1775
1776 @Override
1777 public int getNumberOfVariables() {
1778 return 0;
1779 }
1780
1781 @Override
1782 public double[] getPreviousAcceleration(double[] previousAcceleration) {
1783 return new double[0];
1784 }
1785
1786 @Override
1787 public double[] getScaling() {
1788 return null;
1789 }
1790
1791 @Override
1792 public void setScaling(double[] scaling) {}
1793 @Override
1794 public double getTotalEnergy() {
1795 return 0;
1796 }
1797
1798 @Override
1799 public VARIABLE_TYPE[] getVariableTypes() {
1800 return new VARIABLE_TYPE[0];
1801 }
1802
1803 @Override
1804 public double[] getVelocity(double[] velocity) {
1805 return new double[0];
1806 }
1807
1808 @Override
1809 public void setAcceleration(double[] acceleration) {}
1810 @Override
1811 public void setPreviousAcceleration(double[] previousAcceleration) { }
1812 @Override
1813 public void setVelocity(double[] velocity) {}
1814 };
1815
1816
1817 int n = 2;
1818 double[] x = new double[]{1.0, 7.0};
1819 int m = 3;
1820 double energy = hendersonHasselbach.energy(x);
1821 double[] grad = new double[n];
1822 hendersonHasselbach.energyAndGradient(x, grad);
1823 hendersonHasselbach.setScaling(new double[]{1.0, 1.0});
1824 double eps = 1e-5;
1825 int maxIterations = 100;
1826 OptimizationListener listener = new OptimizationListener() {
1827 @Override
1828 public boolean optimizationUpdate(int iter, int nBFGS, int nFunctionEvals, double gradientRMS,
1829 double coordinateRMS, double f, double df, double angle,
1830 LineSearch.LineSearchResult info) {
1831 return true;
1832 }
1833 };
1834
1835 int statuspKa = LBFGS.minimize(n, m, x, energy, grad, eps, maxIterations,
1836 hendersonHasselbach, listener);
1837
1838 return new double[]{x[0], x[1]};
1839 }
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871 public enum Titration {
1872 ASHtoASP(3.94, -70.35, -35.35,-45.39, -23.15, 12.730, -107.430, 166.369, 0.0, AminoAcid3.ASH, AminoAcid3.ASP),
1873 ASH1toASH2(Double.NaN, 0.00,0,0,0, 0.0, -35.305, 35.305, 0.0, AminoAcid3.ASH, AminoAcid3.ASH),
1874 GLHtoGLU(4.25, -81.90, -39.71, -55.74, -26.3, 28.024, -131.270, 189.980, 0.0, AminoAcid3.GLH, AminoAcid3.GLU),
1875 GLH1toGLH2(Double.NaN, 0,0,0,0.00, 0.0, -29.395, 29.395, 0.0, AminoAcid3.GLH, AminoAcid3.GLH),
1876 LYStoLYD(10.40, 41.35, 20.0, 41.31, 19.7, 6.752, -78.804, 26.894, 0.0, AminoAcid3.LYS, AminoAcid3.LYD),
1877
1878 CYStoCYD(8.55, -53.1, 0.0, 0.0, 0.0,44.247, -183.990, 226.710, 0.0, AminoAcid3.CYS, AminoAcid3.CYD),
1879 HIStoHID(7.00, 40.20, 20.92, 36.65, 18.83, 0.0, -64.317, 30.350, 0.0, AminoAcid3.HIS, AminoAcid3.HID),
1880 HIStoHIE(6.60, 37.44, 18.14, 34.65, 17.95,0.0, -62.931, 32.000, 0.0,AminoAcid3.HIS, AminoAcid3.HIE),
1881 HIDtoHIE(Double.NaN, 0.00, 0.0, 0.0, 0.0,0.0, -36.830, 34.325, 0.0,AminoAcid3.HID, AminoAcid3.HIE);
1882
1883
1884
1885
1886
1887 public final double pKa;
1888
1889 public final double freeEnergyDiff;
1890 public final double freeEnergyDiff2;
1891 public final double freeEnergyDiffGK;
1892 public final double freeEnergyDiffGK2;
1893 public final double cubic;
1894 public final double quadratic;
1895 public final double linear;
1896 public final double offset;
1897 public final AminoAcid3 protForm;
1898 public final AminoAcid3 deprotForm;
1899
1900
1901
1902
1903 Titration(double pKa, double freeEnergyDiff,double freeEnergyDiff2, double freeEnergyDiffGK,
1904 double freeEnergyDiffGK2, double cubic, double quadratic, double linear, double offset,
1905 AminoAcid3 protForm, AminoAcid3 deprotForm) {
1906 this.pKa = pKa;
1907 this.freeEnergyDiff = freeEnergyDiff;
1908 this.freeEnergyDiff2 = freeEnergyDiff2;
1909 this.freeEnergyDiffGK = freeEnergyDiffGK;
1910 this.freeEnergyDiffGK2 = freeEnergyDiffGK2;
1911 this.cubic = cubic;
1912 this.quadratic = quadratic;
1913 this.linear = linear;
1914 this.offset = offset;
1915 this.protForm = protForm;
1916 this.deprotForm = deprotForm;
1917 }
1918 }
1919 }