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.algorithms.commands.test;
39
40 import ffx.algorithms.cli.AlgorithmsCommand;
41 import ffx.utilities.FFXBinding;
42 import org.apache.commons.math3.special.Erf;
43 import picocli.CommandLine.Command;
44 import picocli.CommandLine.Option;
45 import picocli.CommandLine.Parameters;
46
47 import java.util.List;
48
49 import static java.lang.Math.PI;
50 import static java.lang.Math.exp;
51 import static java.lang.Math.pow;
52 import static java.lang.Math.sqrt;
53 import static java.lang.String.format;
54
55
56
57
58
59
60
61
62
63 @Command(description = " Calculate restraint free energy corrections.", name = "test.Freefix")
64 public class Freefix extends AlgorithmsCommand {
65
66
67
68
69 @Option(names = {"--ri"}, paramLabel = "0.00", defaultValue = "0.00",
70 description = "Constant Inner Radius value.")
71 private double innerRadius;
72
73
74
75
76 @Option(names = {"--fi"}, paramLabel = "0.0", defaultValue = "0.0",
77 description = "Constant Inner Force value.")
78 private double innerForce;
79
80
81
82
83 @Option(names = {"--ro"}, paramLabel = "0.00", defaultValue = "0.00",
84 description = "Constant Outer Radius value.")
85 private double outerRadius;
86
87
88
89
90 @Option(names = {"--fo"}, paramLabel = "15.0", defaultValue = "15.0",
91 description = "Constant Outer Force value.")
92 private double outerForce;
93
94
95
96
97 @Option(names = {"--temp"}, paramLabel = "298.0", defaultValue = "298.0",
98 description = "Constant Temperature value.")
99 private double temperature;
100
101
102
103
104 @Parameters(arity = "1..*", paramLabel = "files",
105 description = "Atomic coordinate files in PDB or XYZ format.")
106 private List<String> filenames;
107
108 public static final double AVOGADRO = 6.02214076e23;
109 public static final double STD_CONVERSION = 1.0e27 / AVOGADRO;
110
111
112
113
114 public Freefix() {
115 super();
116 }
117
118
119
120
121
122 public Freefix(FFXBinding binding) {
123 super(binding);
124 }
125
126
127
128
129
130 public Freefix(String[] args) {
131 super(args);
132 }
133
134
135
136
137 @Override
138 public Freefix run() {
139
140
141 if (!init()) {
142 return this;
143 }
144
145 if (innerForce == 0.0) {
146 innerForce = 1.0;
147 innerRadius = 0.0;
148 }
149 if (outerForce == 0.0) {
150 outerForce = 1.0;
151 }
152
153 System.out.printf("%-35s %.4f Ang%n", "Inner Flat-Bottom Radius:", innerRadius);
154 System.out.printf("%-35s %.4f Kcal/mole/Ang^2%n", "Inner Force Constant:", innerForce);
155 System.out.printf("%-35s %.4f Ang%n", "Outer Flat-Bottom Radius:", outerRadius);
156 System.out.printf("%-35s %.4f Kcal/mole/Ang^2%n", "Outer Force Constant:", outerForce);
157 System.out.printf("%-35s %.4f Kelvin%n%n", "System Temperature Value:", temperature);
158
159 double kB = 0.0019872041;
160 double kt = kB * temperature;
161
162 double[] volumeResults = computeVolumeIntegrals(innerRadius, innerForce, outerRadius, outerForce, temperature);
163 double vol = volumeResults[0];
164 double dvol = volumeResults[1];
165
166 logger.info(
167 format("%-35s %.4f Ang^3%n", "Analytical Volume Integral:", vol));
168 logger.info(
169 format("%-35s %.4f Ang^3/K%n", "Analytical dVol/dT Value:", dvol));
170
171 double dg = -kt * Math.log(vol / STD_CONVERSION);
172 double ds = -dg / temperature + kt * dvol / vol;
173 double dh = dg + temperature * ds;
174
175 logger.info(
176 format("%-35s %.4f Kcal/mole%n", "Restraint Free Energy:", dg));
177 logger.info(
178 format("%-35s %.4f Kcal/mole/K%n", "Restraint Entropy Value:", ds));
179 logger.info(
180 format("%-35s %.4f Kcal/mole%n", "Restraint Enthalpy Value:", dh));
181 logger.info(
182 format("%-35s %.4f Kcal/mole%n", "Restraint -T deltaS Value:", -temperature * ds));
183
184 return this;
185 }
186
187
188
189
190
191
192
193
194
195
196
197 public static double[] computeVolumeIntegrals(double innerRadius, double innerForce,
198 double outerRadius, double outerForce, double temperature) {
199 double kB = 0.0019872041;
200 double kt = kB * temperature;
201 double volume1 = 0.0, volume2, volume3 = 0.0;
202
203 if (innerRadius != 0.0) {
204 double term1_v1 = 2.0 * PI * innerRadius * (-2.0 + exp(-pow(innerRadius, 2) * innerForce / kt)) * kt / innerForce;
205 double term2_v1 = sqrt(kt * pow(PI / innerForce, 3)) *
206 (2.0 * innerForce * pow(innerRadius, 2) + kt) * Erf.erf(innerRadius * sqrt(innerForce / kt));
207 volume1 = term1_v1 + term2_v1;
208 }
209
210 volume2 = (4.0 / 3.0) * PI * (pow(outerRadius, 3) - pow(innerRadius, 3));
211
212 if (outerRadius == 0.0) {
213 double term1_v3 = sqrt(kt * pow(PI / outerForce, 3)) * kt;
214 volume3 = term1_v3;
215 } else {
216 double term1_v3 = sqrt(kt * pow(PI / outerForce, 3)) *
217 (2.0 * outerForce * pow(outerRadius, 2) + kt + 4.0 * outerRadius * sqrt(kt * outerForce / PI));
218 volume3 = term1_v3;
219 }
220
221 double volume = volume1 + volume2 + volume3;
222
223 double dv1 = (innerRadius != 0.0) ?
224 computeDv1(innerRadius, innerForce, kt, temperature) : 0.0;
225 double dv3 = (outerRadius != 0.0) ?
226 computeDv3(outerRadius, outerForce, kt, temperature) :
227 1.5 * pow(kt * PI / outerForce, 1.5) / temperature;
228
229 double dvolume = dv1 + dv3;
230 return new double[]{volume, dvolume};
231 }
232
233
234
235
236
237
238
239
240
241
242 private static double computeDv1(double innerRadius, double innerForce, double kt, double temperature) {
243 double term1_dv1 = 2.0 * PI * pow(innerRadius, 3) * exp(-pow(innerRadius, 2) * innerForce / kt) / temperature;
244 double term2_dv1 = 2.0 * PI * innerRadius * (-2.0 + exp(-pow(innerRadius, 2) * innerForce / kt)) * kt / (innerForce * temperature);
245 double term3_dv1 = 0.5 * sqrt(pow(PI / innerForce, 3)) * sqrt(kt) *
246 (2.0 * innerForce * pow(innerRadius, 2) + kt) * Erf.erf(innerRadius * sqrt(innerForce / kt)) / temperature;
247 double term4_dv1 = -PI * innerRadius * exp(-pow(innerRadius, 2) * innerForce / kt) *
248 (2.0 * innerForce * pow(innerRadius, 2) + kt) / (innerForce * temperature);
249 double term5_dv1 = sqrt(pow(kt * PI / innerForce, 3)) * Erf.erf(innerRadius * sqrt(innerForce / kt)) / temperature;
250 return term1_dv1 + term2_dv1 + term3_dv1 + term4_dv1 + term5_dv1;
251 }
252
253
254
255
256
257
258
259
260
261
262 private static double computeDv3(double outerRadius, double outerForce, double kt, double temperature) {
263 double term1_dv3 = sqrt(kt * pow(PI / outerForce, 3)) * outerForce * pow(outerRadius, 2) / temperature;
264 double term2_dv3 = 4.0 * kt * (PI / outerForce) * outerRadius / temperature;
265 double term3_dv3 = 1.5 * sqrt(pow(kt * PI / outerForce, 3)) / temperature;
266 return term1_dv3 + term2_dv3 + term3_dv3;
267 }
268 }