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.xray;
39
40 import ffx.crystal.Crystal;
41 import ffx.crystal.CrystalPotential;
42 import ffx.potential.bonded.Atom;
43 import ffx.potential.bonded.Bond;
44 import ffx.potential.bonded.LambdaInterface;
45 import ffx.potential.bonded.Molecule;
46 import ffx.potential.bonded.Residue;
47 import ffx.potential.parameters.ForceField;
48 import ffx.xray.RefinementMinimize.RefinementMode;
49
50 import java.util.List;
51 import java.util.logging.Logger;
52
53 import static ffx.numerics.math.MatrixMath.determinant3;
54 import static ffx.numerics.math.ScalarMath.b2u;
55 import static ffx.numerics.math.ScalarMath.u2b;
56 import static ffx.utilities.Constants.KCAL_TO_GRAM_ANG2_PER_PS2;
57 import static ffx.utilities.Constants.kB;
58 import static java.lang.String.format;
59 import static java.lang.System.arraycopy;
60 import static java.util.Arrays.fill;
61 import static org.apache.commons.math3.util.FastMath.PI;
62
63
64
65
66
67
68
69
70 public class XRayEnergy implements LambdaInterface, CrystalPotential {
71
72 private static final Logger logger = Logger.getLogger(XRayEnergy.class.getName());
73 private static final double kBkcal = kB / KCAL_TO_GRAM_ANG2_PER_PS2;
74 private static final double eightPI2 = 8.0 * PI * PI;
75 private static final double eightPI23 = eightPI2 * eightPI2 * eightPI2;
76
77 private final DiffractionData diffractionData;
78 private final RefinementModel refinementModel;
79 private final Atom[] activeAtomArray;
80 private final int nAtoms;
81 private final double bMass;
82 private final double kTbNonzero;
83 private final double kTbSimWeight;
84 private final double occMass;
85 private final boolean lambdaTerm;
86 private final double[] g2;
87 private final double[] dUdXdL;
88 protected double lambda = 1.0;
89 private int nXYZ;
90 private int nB;
91 private int nOCC;
92 private RefinementMode refinementMode;
93 private boolean refineXYZ = false;
94 private boolean refineOCC = false;
95 private boolean refineB = false;
96 private boolean xrayTerms = true;
97 private boolean restraintTerms = true;
98 private double[] optimizationScaling = null;
99 private double totalEnergy;
100 private double dEdL;
101 private STATE state = STATE.BOTH;
102
103
104
105
106
107
108
109
110
111
112
113 public XRayEnergy(
114 DiffractionData diffractionData, int nXYZ, int nB, int nOCC, RefinementMode refinementMode) {
115 this.diffractionData = diffractionData;
116 this.refinementModel = diffractionData.getRefinementModel();
117 this.refinementMode = refinementMode;
118 this.nXYZ = nXYZ;
119 this.nB = nB;
120 this.nOCC = nOCC;
121
122 Atom[] atomArray = refinementModel.getTotalAtomArray();
123 this.nAtoms = atomArray.length;
124
125 bMass = diffractionData.getbMass();
126 double temperature = 50.0;
127 kTbNonzero = 0.5 * kBkcal * temperature * diffractionData.getbNonZeroWeight();
128 kTbSimWeight = kBkcal * temperature * diffractionData.getbSimWeight();
129 occMass = diffractionData.getOccMass();
130
131 ForceField forceField = diffractionData.getAssembly()[0].getForceField();
132 lambdaTerm = forceField.getBoolean("LAMBDATERM", false);
133
134
135 int count = 0;
136 for (Atom a : atomArray) {
137 if (a.isActive()) {
138 count++;
139 }
140 }
141 activeAtomArray = new Atom[count];
142 count = 0;
143 for (Atom a : atomArray) {
144 if (a.isActive()) {
145 activeAtomArray[count++] = a;
146 }
147 }
148
149 dUdXdL = new double[count * 3];
150 g2 = new double[count * 3];
151
152 setRefinementBooleans();
153
154 if (refineB) {
155 logger.info(" B-Factor Refinement Parameters");
156 logger.info(" Temperature: " + temperature);
157 logger.info(" Non-zero restraint weight: " + diffractionData.getbNonZeroWeight());
158 logger.info(" Similarity restraint weight: " + diffractionData.getbSimWeight());
159 }
160 }
161
162
163 @Override
164 public boolean destroy() {
165 return diffractionData.destroy();
166 }
167
168
169 @Override
170 public double energy(double[] x) {
171 double e = 0.0;
172
173
174 unscaleCoordinates(x);
175
176 if (refineXYZ) {
177
178 diffractionData.setFFTCoordinates(x);
179 }
180 if (refineB) {
181
182 setBFactors(x);
183 }
184 if (refineOCC) {
185
186 setOccupancies(x);
187 }
188
189 if (xrayTerms) {
190
191 if (lambdaTerm) {
192 diffractionData.setLambdaTerm(false);
193 }
194
195
196 diffractionData.computeAtomicDensity();
197
198 e = diffractionData.computeLikelihood();
199
200 if (lambdaTerm) {
201
202
203 diffractionData.setLambdaTerm(true);
204
205
206 diffractionData.computeAtomicDensity();
207
208
209 double e2 = diffractionData.computeLikelihood();
210
211 dEdL = e - e2;
212
213 e = lambda * e + (1.0 - lambda) * e2;
214
215 diffractionData.setLambdaTerm(false);
216 }
217 }
218
219 if (restraintTerms) {
220 if (refineB) {
221
222 e += getBFactorRestraints();
223 }
224 }
225
226
227 scaleCoordinates(x);
228
229 totalEnergy = e;
230 return e;
231 }
232
233
234 @Override
235 public double energyAndGradient(double[] x, double[] g) {
236 double e = 0.0;
237
238
239 unscaleCoordinates(x);
240
241 if (refineXYZ) {
242 for (Atom a : activeAtomArray) {
243 a.setXYZGradient(0.0, 0.0, 0.0);
244 a.setLambdaXYZGradient(0.0, 0.0, 0.0);
245 }
246
247
248 diffractionData.setFFTCoordinates(x);
249 }
250
251 if (refineB) {
252 for (Atom a : activeAtomArray) {
253 a.setTempFactorGradient(0.0);
254 if (a.getAnisou(null) != null) {
255 if (a.getAnisouGradient(null) == null) {
256 double[] ganisou = new double[6];
257 a.setAnisouGradient(ganisou);
258 } else {
259 double[] ganisou = a.getAnisouGradient(null);
260 ganisou[0] = ganisou[1] = ganisou[2] = 0.0;
261 ganisou[3] = ganisou[4] = ganisou[5] = 0.0;
262 a.setAnisouGradient(ganisou);
263 }
264 }
265 }
266
267
268 setBFactors(x);
269 }
270
271 if (refineOCC) {
272 for (Atom a : activeAtomArray) {
273 a.setOccupancyGradient(0.0);
274 }
275
276
277 setOccupancies(x);
278 }
279
280 if (xrayTerms) {
281
282 if (lambdaTerm) {
283 diffractionData.setLambdaTerm(false);
284 }
285
286
287 diffractionData.computeAtomicDensity();
288
289
290 e = diffractionData.computeLikelihood();
291
292
293 diffractionData.computeAtomicGradients(refinementMode);
294
295 if (refineXYZ) {
296
297 getXYZGradients(g);
298 }
299
300 if (lambdaTerm) {
301
302 int n = dUdXdL.length;
303 arraycopy(g, 0, dUdXdL, 0, n);
304
305 for (Atom a : activeAtomArray) {
306 a.setXYZGradient(0.0, 0.0, 0.0);
307 a.setLambdaXYZGradient(0.0, 0.0, 0.0);
308 }
309
310
311 diffractionData.setLambdaTerm(true);
312
313
314 diffractionData.computeAtomicDensity();
315
316
317 double e2 = diffractionData.computeLikelihood();
318
319
320 diffractionData.computeAtomicGradients(refinementMode);
321
322 dEdL = e - e2;
323 e = lambda * e + (1.0 - lambda) * e2;
324 getXYZGradients(g2);
325 for (int i = 0; i < g.length; i++) {
326 dUdXdL[i] -= g2[i];
327 g[i] = lambda * g[i] + (1.0 - lambda) * g2[i];
328 }
329
330 diffractionData.setLambdaTerm(false);
331 }
332 }
333
334 if (restraintTerms) {
335 if (refineB) {
336
337 e += getBFactorRestraints();
338
339
340 getBFactorGradients(g);
341 }
342
343 if (refineOCC) {
344
345 getOccupancyGradients(g);
346 }
347 }
348
349
350 scaleCoordinatesAndGradient(x, g);
351
352 totalEnergy = e;
353 return e;
354 }
355
356
357 @Override
358 public double[] getAcceleration(double[] acceleration) {
359 throw new UnsupportedOperationException("Not supported yet.");
360 }
361
362
363 @Override
364 public double[] getCoordinates(double[] x) {
365 assert (x != null);
366 double[] xyz = new double[3];
367 int index = 0;
368 fill(x, 0.0);
369
370 if (refineXYZ) {
371 for (Atom a : activeAtomArray) {
372 a.getXYZ(xyz);
373 x[index++] = xyz[0];
374 x[index++] = xyz[1];
375 x[index++] = xyz[2];
376 }
377 }
378
379 if (refineB) {
380 double[] anisou = null;
381 int resnum = -1;
382 int nat = 0;
383 int nres = diffractionData.getnResidueBFactor() + 1;
384 for (Atom a : activeAtomArray) {
385
386 if (a.getAtomicNumber() == 1) {
387 continue;
388 }
389 if (a.getAnisou(null) != null) {
390 anisou = a.getAnisou(anisou);
391 x[index++] = anisou[0];
392 x[index++] = anisou[1];
393 x[index++] = anisou[2];
394 x[index++] = anisou[3];
395 x[index++] = anisou[4];
396 x[index++] = anisou[5];
397 } else if (diffractionData.isResidueBFactor()) {
398 if (resnum != a.getResidueNumber()) {
399 if (nres >= diffractionData.getnResidueBFactor()) {
400 if (resnum > -1 && index < nXYZ + nB - 1) {
401 x[index] /= nat;
402 index++;
403 }
404 nat = 1;
405 nres = 1;
406 } else {
407 nres++;
408 nat++;
409 }
410 x[index] += a.getTempFactor();
411 resnum = a.getResidueNumber();
412 } else {
413 x[index] += a.getTempFactor();
414 nat++;
415 }
416 } else {
417 x[index++] = a.getTempFactor();
418 }
419 }
420
421 if (diffractionData.isResidueBFactor()) {
422 if (nat > 1) {
423 x[index] /= nat;
424 }
425 }
426 }
427
428 if (refineOCC) {
429 for (List<Residue> list : refinementModel.getAltResidues()) {
430 for (Residue r : list) {
431 for (Atom a : r.getAtomList()) {
432 if (a.getOccupancy() < 1.0) {
433 x[index++] = a.getOccupancy();
434 break;
435 }
436 }
437 }
438 }
439 for (List<Molecule> list : refinementModel.getAltMolecules()) {
440 for (Molecule m : list) {
441 for (Atom a : m.getAtomList()) {
442 if (a.getOccupancy() < 1.0) {
443 x[index++] = a.getOccupancy();
444 break;
445 }
446 }
447 }
448 }
449 }
450
451 return x;
452 }
453
454
455 @Override
456 public Crystal getCrystal() {
457 return diffractionData.getCrystal()[0];
458 }
459
460
461 @Override
462 public void setCrystal(Crystal crystal) {
463 logger.severe(" XRayEnergy does implement setCrystal yet.");
464 }
465
466
467 @Override
468 public STATE getEnergyTermState() {
469 return state;
470 }
471
472
473 @Override
474 public void setEnergyTermState(STATE state) {
475 this.state = state;
476 switch (state) {
477 case FAST:
478 xrayTerms = false;
479 restraintTerms = true;
480 break;
481 case SLOW:
482 xrayTerms = true;
483 restraintTerms = false;
484 break;
485 default:
486 xrayTerms = true;
487 restraintTerms = true;
488 }
489 }
490
491
492 @Override
493 public double getLambda() {
494 return lambda;
495 }
496
497
498 @Override
499 public void setLambda(double lambda) {
500 if (lambda <= 1.0 && lambda >= 0.0) {
501 this.lambda = lambda;
502 } else {
503 String message = format("Lambda value %8.3f is not in the range [0..1].", lambda);
504 logger.warning(message);
505 }
506 }
507
508
509 @Override
510 public double[] getMass() {
511 double[] mass = new double[nXYZ + nB + nOCC];
512 int i = 0;
513 if (refineXYZ) {
514 for (Atom a : activeAtomArray) {
515 double m = a.getMass();
516 mass[i++] = m;
517 mass[i++] = m;
518 mass[i++] = m;
519 }
520 }
521
522 if (refineB) {
523 for (int j = i; j < nXYZ + nB; i++, j++) {
524 mass[j] = bMass;
525 }
526 }
527
528 if (refineOCC) {
529 for (int j = i; j < nXYZ + nB + nOCC; i++, j++) {
530 mass[j] = occMass;
531 }
532 }
533 return mass;
534 }
535
536
537
538
539
540
541 public int getNB() {
542 return nB;
543 }
544
545
546
547
548
549
550 public void setNB(int nB) {
551 this.nB = nB;
552 }
553
554
555
556
557
558
559 public int getNOcc() {
560 return nOCC;
561 }
562
563
564
565
566
567
568 public void setNOcc(int nOCC) {
569 this.nOCC = nOCC;
570 }
571
572
573
574
575
576
577 public int getNXYZ() {
578 return nXYZ;
579 }
580
581
582
583
584
585
586 public void setNXYZ(int nXYZ) {
587 this.nXYZ = nXYZ;
588 }
589
590
591 @Override
592 public int getNumberOfVariables() {
593 return nXYZ + nB + nOCC;
594 }
595
596
597 @Override
598 public double[] getPreviousAcceleration(double[] previousAcceleration) {
599 throw new UnsupportedOperationException("Not supported yet.");
600 }
601
602
603
604
605
606
607 public RefinementMode getRefinementMode() {
608 return refinementMode;
609 }
610
611
612
613
614
615
616 public void setRefinementMode(RefinementMode refinementmode) {
617 this.refinementMode = refinementmode;
618 setRefinementBooleans();
619 }
620
621
622 @Override
623 public double[] getScaling() {
624 return optimizationScaling;
625 }
626
627
628 @Override
629 public void setScaling(double[] scaling) {
630 optimizationScaling = scaling;
631 }
632
633
634 @Override
635 public double getTotalEnergy() {
636 return totalEnergy;
637 }
638
639
640
641
642
643
644 @Override
645 public VARIABLE_TYPE[] getVariableTypes() {
646 VARIABLE_TYPE[] vtypes = new VARIABLE_TYPE[nXYZ + nB + nOCC];
647 int i = 0;
648 if (refineXYZ) {
649 for (Atom a : activeAtomArray) {
650 vtypes[i++] = VARIABLE_TYPE.X;
651 vtypes[i++] = VARIABLE_TYPE.Y;
652 vtypes[i++] = VARIABLE_TYPE.Z;
653 }
654 }
655
656 if (refineB) {
657 for (int j = i; j < nXYZ + nB; i++, j++) {
658 vtypes[j] = VARIABLE_TYPE.OTHER;
659 }
660 }
661
662 if (refineOCC) {
663 for (int j = i; j < nXYZ + nB + nOCC; i++, j++) {
664 vtypes[j] = VARIABLE_TYPE.OTHER;
665 }
666 }
667 return vtypes;
668 }
669
670
671 @Override
672 public double[] getVelocity(double[] velocity) {
673 throw new UnsupportedOperationException("Not supported yet.");
674 }
675
676
677 @Override
678 public double getd2EdL2() {
679 return 0.0;
680 }
681
682
683 @Override
684 public double getdEdL() {
685 return dEdL;
686 }
687
688
689 @Override
690 public void getdEdXdL(double[] gradient) {
691 int n = dUdXdL.length;
692 arraycopy(dUdXdL, 0, gradient, 0, n);
693 }
694
695
696 @Override
697 public void setAcceleration(double[] acceleration) {
698 throw new UnsupportedOperationException("Not supported yet.");
699 }
700
701
702
703
704
705
706 public void setCoordinates(double[] x) {
707 assert (x != null);
708 double[] xyz = new double[3];
709 int index = 0;
710 for (Atom a : activeAtomArray) {
711 xyz[0] = x[index++];
712 xyz[1] = x[index++];
713 xyz[2] = x[index++];
714 a.moveTo(xyz);
715 }
716 }
717
718
719
720
721
722
723 public void setOccupancies(double[] x) {
724 double occ;
725 int index = nXYZ + nB;
726 for (List<Residue> list : refinementModel.getAltResidues()) {
727 for (Residue r : list) {
728 occ = x[index++];
729 for (Atom a : r.getAtomList()) {
730 if (a.getOccupancy() < 1.0) {
731 a.setOccupancy(occ);
732 }
733 }
734 }
735 }
736 for (List<Molecule> list : refinementModel.getAltMolecules()) {
737 for (Molecule m : list) {
738 occ = x[index++];
739 for (Atom a : m.getAtomList()) {
740 if (a.getOccupancy() < 1.0) {
741 a.setOccupancy(occ);
742 }
743 }
744 }
745 }
746 }
747
748
749 @Override
750 public void setPreviousAcceleration(double[] previousAcceleration) {
751 throw new UnsupportedOperationException("Not supported yet.");
752 }
753
754
755 @Override
756 public void setVelocity(double[] velocity) {
757 throw new UnsupportedOperationException("Not supported yet.");
758 }
759
760
761
762
763
764 private void setRefinementBooleans() {
765
766 refineXYZ = false;
767 refineB = false;
768 refineOCC = false;
769
770 if (refinementMode == RefinementMode.COORDINATES
771 || refinementMode == RefinementMode.COORDINATES_AND_BFACTORS
772 || refinementMode == RefinementMode.COORDINATES_AND_OCCUPANCIES
773 || refinementMode == RefinementMode.COORDINATES_AND_BFACTORS_AND_OCCUPANCIES) {
774 refineXYZ = true;
775 }
776
777 if (refinementMode == RefinementMode.BFACTORS
778 || refinementMode == RefinementMode.BFACTORS_AND_OCCUPANCIES
779 || refinementMode == RefinementMode.COORDINATES_AND_BFACTORS
780 || refinementMode == RefinementMode.COORDINATES_AND_BFACTORS_AND_OCCUPANCIES) {
781 refineB = true;
782 }
783
784 if (refinementMode == RefinementMode.OCCUPANCIES
785 || refinementMode == RefinementMode.BFACTORS_AND_OCCUPANCIES
786 || refinementMode == RefinementMode.COORDINATES_AND_OCCUPANCIES
787 || refinementMode == RefinementMode.COORDINATES_AND_BFACTORS_AND_OCCUPANCIES) {
788 refineOCC = true;
789 }
790 }
791
792
793
794
795
796
797 private void getBFactorGradients(double[] g) {
798 assert (g != null);
799 double[] grad = null;
800 int index = nXYZ;
801 int resnum = -1;
802 int nres = diffractionData.getnResidueBFactor() + 1;
803 for (Atom a : activeAtomArray) {
804
805 if (a.getAtomicNumber() == 1) {
806 continue;
807 }
808 if (a.getAnisou(null) != null) {
809 grad = a.getAnisouGradient(grad);
810 g[index++] = grad[0];
811 g[index++] = grad[1];
812 g[index++] = grad[2];
813 g[index++] = grad[3];
814 g[index++] = grad[4];
815 g[index++] = grad[5];
816 } else if (diffractionData.isResidueBFactor()) {
817 if (resnum != a.getResidueNumber()) {
818 if (nres >= diffractionData.getnResidueBFactor()) {
819 if (resnum > -1 && index < nXYZ + nB - 1) {
820 index++;
821 }
822 nres = 1;
823 } else {
824 nres++;
825 }
826 g[index] += a.getTempFactorGradient();
827 resnum = a.getResidueNumber();
828 } else {
829 g[index] += a.getTempFactorGradient();
830 }
831 } else {
832 g[index++] = a.getTempFactorGradient();
833 }
834 }
835 }
836
837
838
839
840
841
842
843 private void getOccupancyGradients(double[] g) {
844 double ave;
845 int index = nXYZ + nB;
846
847
848 for (List<Residue> list : refinementModel.getAltResidues()) {
849 ave = 0.0;
850 for (Residue r : list) {
851 for (Atom a : r.getAtomList()) {
852 if (a.getOccupancy() < 1.0) {
853 ave += a.getOccupancyGradient();
854 }
855 }
856 }
857
858
859
860
861 ave /= list.size();
862 for (Residue r : list) {
863 for (Atom a : r.getAtomList()) {
864 if (a.getOccupancy() < 1.0) {
865 g[index] += a.getOccupancyGradient();
866 }
867 }
868 if (list.size() > 1) {
869
870 g[index] -= ave;
871 }
872 index++;
873 }
874 }
875
876
877 for (List<Molecule> list : refinementModel.getAltMolecules()) {
878 ave = 0.0;
879 for (Molecule m : list) {
880 for (Atom a : m.getAtomList()) {
881 if (a.getOccupancy() < 1.0) {
882 ave += a.getOccupancyGradient();
883 }
884 }
885 }
886 ave /= list.size();
887 for (Molecule m : list) {
888 for (Atom a : m.getAtomList()) {
889 if (a.getOccupancy() < 1.0) {
890 g[index] += a.getOccupancyGradient();
891 }
892 }
893 if (list.size() > 1) {
894 g[index] -= ave;
895 }
896 index++;
897 }
898 }
899 }
900
901
902
903
904
905
906 private void getXYZGradients(double[] g) {
907 assert (g != null);
908 double[] grad = new double[3];
909 int index = 0;
910 for (Atom a : activeAtomArray) {
911 a.getXYZGradient(grad);
912 g[index++] = grad[0];
913 g[index++] = grad[1];
914 g[index++] = grad[2];
915 }
916 }
917
918
919
920
921
922
923 private void setBFactors(double[] x) {
924 double[] tmpanisou = new double[6];
925 int index = nXYZ;
926 int nneg = 0;
927 int resnum = -1;
928 int nres = diffractionData.getnResidueBFactor() + 1;
929 for (Atom a : activeAtomArray) {
930
931 if (a.getAtomicNumber() == 1) {
932 continue;
933 }
934 if (a.getAnisou(null) == null) {
935 double biso = x[index];
936 if (diffractionData.isResidueBFactor()) {
937 if (resnum != a.getResidueNumber()) {
938 if (nres >= diffractionData.getnResidueBFactor()) {
939 if (resnum > -1 && index < nXYZ + nB - 1) {
940 index++;
941 biso = x[index];
942 }
943 nres = 1;
944 } else {
945 nres++;
946 }
947 resnum = a.getResidueNumber();
948 }
949 } else {
950 index++;
951 }
952
953 if (biso > 0.0) {
954 a.setTempFactor(biso);
955 } else {
956 nneg++;
957 a.setTempFactor(0.01);
958 if (nneg < 5) {
959 logger.info(" Isotropic atom: " + a + " negative B factor");
960 }
961 }
962 } else {
963 double[] anisou = a.getAnisou(null);
964 tmpanisou[0] = x[index++];
965 tmpanisou[1] = x[index++];
966 tmpanisou[2] = x[index++];
967 tmpanisou[3] = x[index++];
968 tmpanisou[4] = x[index++];
969 tmpanisou[5] = x[index++];
970 double det = determinant3(tmpanisou);
971 if (det > 0.0) {
972 arraycopy(tmpanisou, 0, anisou, 0, 6);
973 a.setAnisou(anisou);
974 det = Math.pow(det, 0.3333);
975 a.setTempFactor(u2b(det));
976 } else {
977 nneg++;
978 a.setTempFactor(0.01);
979 anisou[0] = anisou[1] = anisou[2] = b2u(0.01);
980 anisou[3] = anisou[4] = anisou[5] = 0.0;
981 a.setAnisou(anisou);
982 if (nneg < 5) {
983 logger.info(" Anisotropic atom: " + a + " negative ANISOU");
984 }
985 }
986 }
987 }
988
989 if (nneg > 0) {
990 logger.info(
991 " "
992 + nneg
993 + " of "
994 + nAtoms
995 + " atoms with negative B factors! Attempting to correct.\n (If this problem persists, increase bsimweight)");
996 }
997
998
999 for (Atom a : activeAtomArray) {
1000 if (a.getAtomicNumber() == 1) {
1001 Atom b = a.getBonds().get(0).get1_2(a);
1002 a.setTempFactor(b.getTempFactor());
1003 }
1004 }
1005 }
1006
1007
1008
1009
1010
1011
1012
1013 private double getBFactorRestraints() {
1014 Atom a1, a2;
1015 double b1, b2, bdiff;
1016 double[] anisou1 = null;
1017 double[] anisou2 = null;
1018 double gradb;
1019 double det1, det2;
1020 double[] gradu = new double[6];
1021 double e = 0.0;
1022
1023 for (Atom a : activeAtomArray) {
1024 double biso = a.getTempFactor();
1025
1026 if (a.getAtomicNumber() == 1) {
1027 continue;
1028 }
1029
1030 if (a.getAnisou(null) == null) {
1031
1032
1033 e += -3.0 * kTbNonzero * Math.log(biso / (4.0 * Math.PI));
1034 gradb = -3.0 * kTbNonzero / biso;
1035 a.addToTempFactorGradient(gradb);
1036
1037
1038 List<Bond> bonds = a.getBonds();
1039 for (Bond b : bonds) {
1040 if (a.compareTo(b.getAtom(0)) == 0) {
1041 a1 = b.getAtom(0);
1042 a2 = b.getAtom(1);
1043 } else {
1044 a1 = b.getAtom(1);
1045 a2 = b.getAtom(0);
1046 }
1047 if (a2.getAtomicNumber() == 1) {
1048 continue;
1049 }
1050 if (a2.getIndex() < a1.getIndex()) {
1051 continue;
1052 }
1053 if (!a1.getAltLoc().equals(' ')
1054 && !a1.getAltLoc().equals('A')
1055 && a2.getAltLoc().equals(' ')) {
1056 continue;
1057 }
1058
1059 b1 = a1.getTempFactor();
1060 b2 = a2.getTempFactor();
1061
1062 bdiff = b2u(b1 - b2);
1063 e += kTbSimWeight * Math.pow(bdiff, 2.0);
1064 gradb = 2.0 * kTbSimWeight * bdiff;
1065 a1.addToTempFactorGradient(gradb);
1066 a2.addToTempFactorGradient(-gradb);
1067 }
1068 } else {
1069
1070 anisou1 = a.getAnisou(anisou1);
1071 det1 = determinant3(anisou1);
1072
1073
1074 e += u2b(-kTbNonzero * Math.log(det1 * eightPI2 * Math.PI));
1075 gradu[0] = u2b(-kTbNonzero * ((anisou1[1] * anisou1[2] - anisou1[5] * anisou1[5]) / det1));
1076 gradu[1] = u2b(-kTbNonzero * ((anisou1[0] * anisou1[2] - anisou1[4] * anisou1[4]) / det1));
1077 gradu[2] = u2b(-kTbNonzero * ((anisou1[0] * anisou1[1] - anisou1[3] * anisou1[3]) / det1));
1078 gradu[3] =
1079 u2b(-kTbNonzero * ((2.0 * (anisou1[4] * anisou1[5] - anisou1[3] * anisou1[2])) / det1));
1080 gradu[4] =
1081 u2b(-kTbNonzero * ((2.0 * (anisou1[3] * anisou1[5] - anisou1[4] * anisou1[1])) / det1));
1082 gradu[5] =
1083 u2b(-kTbNonzero * ((2.0 * (anisou1[3] * anisou1[4] - anisou1[5] * anisou1[0])) / det1));
1084 a.addToAnisouGradient(gradu);
1085
1086
1087 List<Bond> bonds = a.getBonds();
1088 for (Bond b : bonds) {
1089 if (a.compareTo(b.getAtom(0)) == 0) {
1090 a1 = b.getAtom(0);
1091 a2 = b.getAtom(1);
1092 } else {
1093 a1 = b.getAtom(1);
1094 a2 = b.getAtom(0);
1095 }
1096 if (a2.getAtomicNumber() == 1) {
1097 continue;
1098 }
1099 if (a2.getIndex() < a1.getIndex()) {
1100 continue;
1101 }
1102 if (a2.getAnisou(null) == null) {
1103 continue;
1104 }
1105 if (!a1.getAltLoc().equals(' ')
1106 && !a1.getAltLoc().equals('A')
1107 && a2.getAltLoc().equals(' ')) {
1108 continue;
1109 }
1110
1111 anisou2 = a2.getAnisou(anisou2);
1112 det2 = determinant3(anisou2);
1113 bdiff = det1 - det2;
1114 e += eightPI23 * kTbSimWeight * Math.pow(bdiff, 2.0);
1115 gradb = eightPI23 * 2.0 * kTbSimWeight * bdiff;
1116
1117
1118 gradu[0] = gradb * (anisou1[1] * anisou1[2] - anisou1[5] * anisou1[5]);
1119 gradu[1] = gradb * (anisou1[0] * anisou1[2] - anisou1[4] * anisou1[4]);
1120 gradu[2] = gradb * (anisou1[0] * anisou1[1] - anisou1[3] * anisou1[3]);
1121 gradu[3] = gradb * (2.0 * (anisou1[4] * anisou1[5] - anisou1[3] * anisou1[2]));
1122 gradu[4] = gradb * (2.0 * (anisou1[3] * anisou1[5] - anisou1[4] * anisou1[1]));
1123 gradu[5] = gradb * (2.0 * (anisou1[3] * anisou1[4] - anisou1[5] * anisou1[0]));
1124 a1.addToAnisouGradient(gradu);
1125
1126
1127 gradu[0] = gradb * (anisou2[5] * anisou2[5] - anisou2[1] * anisou2[2]);
1128 gradu[1] = gradb * (anisou2[4] * anisou2[4] - anisou2[0] * anisou2[2]);
1129 gradu[2] = gradb * (anisou2[3] * anisou2[3] - anisou2[0] * anisou2[1]);
1130 gradu[3] = gradb * (2.0 * (anisou2[3] * anisou2[2] - anisou2[4] * anisou2[5]));
1131 gradu[4] = gradb * (2.0 * (anisou2[4] * anisou2[1] - anisou2[3] * anisou2[5]));
1132 gradu[5] = gradb * (2.0 * (anisou2[5] * anisou2[0] - anisou2[3] * anisou2[4]));
1133 a2.addToAnisouGradient(gradu);
1134 }
1135 }
1136 }
1137 return e;
1138 }
1139 }