1 // ******************************************************************************
2 //
3 // Title: Force Field X.
4 // Description: Force Field X - Software for Molecular Biophysics.
5 // Copyright: Copyright (c) Michael J. Schnieders 2001-2025.
6 //
7 // This file is part of Force Field X.
8 //
9 // Force Field X is free software; you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License version 3 as published by
11 // the Free Software Foundation.
12 //
13 // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 // details.
17 //
18 // You should have received a copy of the GNU General Public License along with
19 // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20 // Place, Suite 330, Boston, MA 02111-1307 USA
21 //
22 // Linking this library statically or dynamically with other modules is making a
23 // combined work based on this library. Thus, the terms and conditions of the
24 // GNU General Public License cover the whole combination.
25 //
26 // As a special exception, the copyright holders of this library give you
27 // permission to link this library with independent modules to produce an
28 // executable, regardless of the license terms of these independent modules, and
29 // to copy and distribute the resulting executable under terms of your choice,
30 // provided that you also meet, for each linked independent module, the terms
31 // and conditions of the license of that module. An independent module is a
32 // module which is not derived from or based on this library. If you modify this
33 // library, you may extend this exception to your version of the library, but
34 // you are not obligated to do so. If you do not wish to do so, delete this
35 // exception statement from your version.
36 //
37 // ******************************************************************************
38 package ffx.algorithms.cli;
39
40 import ffx.algorithms.dynamics.Barostat;
41 import ffx.crystal.CrystalPotential;
42 import ffx.potential.MolecularAssembly;
43 import picocli.CommandLine.ArgGroup;
44 import picocli.CommandLine.Option;
45
46 import java.util.logging.Logger;
47
48 import static java.lang.Double.parseDouble;
49 import static java.lang.Integer.parseInt;
50 import static java.lang.String.format;
51
52 /**
53 * Represents command line options for scripts that use a barostat/NPT.
54 *
55 * @author Michael J. Schnieders
56 * @author Hernan V. Bernabe
57 * @since 1.0
58 */
59 public class BarostatOptions {
60
61 /**
62 * Default maximum density constraint on the barostat that prevents reduction in unit cell
63 * (particularly at or near vapor states).
64 */
65 public static final String DEFAULT_MAX_DENSITY = "1.6";
66 /**
67 * Default "tin box" constraint on the barostat that prevents expansion of the unit cell
68 * (particularly at or near vapor states).
69 */
70 public static final String DEFAULT_MIN_DENSITY = "0.75";
71 /**
72 * Default width of proposed crystal angle moves (uniformly distributed) in degrees.
73 */
74 public static final String DEFAULT_MAX_ANGLE_MOVE = "0.5";
75 /**
76 * Default size of proposed unit cell volume moves (uniformly distributed) in Angstroms^3.
77 */
78 public static final String DEFAULT_MAX_VOLUME_MOVE = "1.0";
79 /**
80 * Default mean number of MD steps (Poisson distribution) between barostat move proposals.
81 */
82 public static final String DEFAULT_BAROSTAT_INTERVAL = "10";
83 /**
84 * Default number of Barostat moves between print statements.
85 */
86 public static final String DEFAULT_BAROSTAT_PRINT_INTERVAL = "1000";
87
88 private static final Logger logger = Logger.getLogger(BarostatOptions.class.getName());
89
90 /**
91 * The ArgGroup keeps the BarostatOptions together when printing help.
92 */
93 @ArgGroup(heading = "%n Monte Carlo Pressure Options%n", validate = false)
94 private final BarostatOptionGroup group = new BarostatOptionGroup();
95
96 /**
97 * If pressure has been set > 0, creates a Barostat around a CrystalPotential, else returns the
98 * original, unmodified CrystalPotential.
99 *
100 * @param molecularAssembly Primary molecularAssembly of the CrystalPotential.
101 * @param crystalPotential A CrystalPotential.
102 * @return Either a Barostat (NPT enabled) or the CrystalPotential.
103 */
104 public CrystalPotential checkNPT(MolecularAssembly molecularAssembly,
105 CrystalPotential crystalPotential) {
106 if (group.pressure > 0) {
107 return createBarostat(molecularAssembly, crystalPotential);
108 } else {
109 return crystalPotential;
110 }
111 }
112
113 /**
114 * Creates a Barostat around a CrystalPotential.
115 *
116 * @param assembly Primary assembly of the CrystalPotential.
117 * @param crystalPotential A CrystalPotential.
118 * @return An NPT potential.
119 * @throws IllegalArgumentException If this BarostatOptions has pressure <= 0.
120 */
121 public Barostat createBarostat(MolecularAssembly assembly, CrystalPotential crystalPotential)
122 throws IllegalArgumentException {
123 if (group.pressure > 0) {
124 Barostat barostat = new Barostat(assembly, crystalPotential);
125 barostat.setPressure(group.pressure);
126 barostat.setIsotropic(group.isotropic);
127 barostat.setMaxDensity(group.maxD);
128 barostat.setMinDensity(group.minD);
129 barostat.setBarostatPrintFrequency(group.barPrint);
130 double dens = barostat.density();
131 if (dens < group.minD) {
132 logger.info(format(
133 " Barostat: initial density %9.4g < minimum density %9.4g, resetting to minimum density",
134 dens, group.minD));
135 barostat.setDensity(group.minD);
136 } else if (dens > group.maxD) {
137 logger.info(format(
138 " Barostat: initial density %9.4g > maximum density %9.4g, resetting to maximum density",
139 dens, group.maxD));
140 barostat.setDensity(group.maxD);
141 }
142 barostat.setMaxAngleMove(group.maxAM);
143 barostat.setMaxVolumeMove(group.maxV);
144 barostat.setMeanBarostatInterval(group.barInt);
145 return barostat;
146 } else {
147 throw new IllegalArgumentException(" Pressure is <= 0; cannot create a Barostat!");
148 }
149 }
150
151 /**
152 * -p or --npt Specify use of a Monte Carlo Barostat at the given pressure (default 0 = constant
153 * volume).
154 *
155 * @return Returns the pressure (atm).
156 */
157 public double getPressure() {
158 return group.pressure;
159 }
160
161 public void setPressure(double pressure) {
162 group.pressure = pressure;
163 }
164
165 /**
166 * Restrict the MC Barostat to isotropic moves. The lattice angles are * held fixed, and lattice
167 * lengths are scaled equally.
168 *
169 * @return Returns true if the Barostat is isotropic.
170 */
171 public boolean isIsotropic() {
172 return group.isotropic;
173 }
174
175 public void setIsotropic(boolean isotropic) {
176 group.isotropic = isotropic;
177 }
178
179 /**
180 * The maximum density accepted by the MC Barostat (g/cc).
181 *
182 * @return Returns the maximum density.
183 */
184 public double getMaxD() {
185 return group.maxD;
186 }
187
188 public void setMaxD(double maxD) {
189 group.maxD = maxD;
190 }
191
192 /**
193 * The minimum density accepted by the MC Barostat (g/cc).
194 *
195 * @return Returns the minimum density.
196 */
197 public double getMinD() {
198 return group.minD;
199 }
200
201 public void setMinD(double minD) {
202 group.minD = minD;
203 }
204
205 /**
206 * The volume of a proposed unit cell volume moves (uniformly distributed) in Angstroms^3.
207 *
208 * @return Returns the maximum volume move.
209 */
210 public double getMaxV() {
211 return group.maxV;
212 }
213
214 /**
215 * The width of proposed crystal angle moves (uniformly distributed) in degrees.
216 *
217 * @return Returns the width of angle moves.
218 */
219 public double getMaxAM() {
220 return group.maxAM;
221 }
222
223 public void setMaxAM(double maxAM) {
224 group.maxAM = maxAM;
225 }
226
227 public void setMaxV(double maxV) {
228 group.maxV = maxV;
229 }
230
231 /**
232 * The mean number of MD steps (Poisson distribution) between barostat move proposals.
233 *
234 * @return Returns the mean number of MD steps between barostat MC trials.
235 */
236 public int getBarInt() {
237 return group.barInt;
238 }
239
240 public void setBarInt(int barInt) {
241 group.barInt = barInt;
242 }
243
244 /**
245 * --bpi or --barostatPrintInterval Sets the number of Barostat MC cycles between print
246 * statements.
247 */
248 public int getPrintInt() {
249 return group.barPrint;
250 }
251
252 public void setPrintInt(int printInterval) {
253 group.barPrint = printInterval;
254 }
255
256 /**
257 * Collection of Barostat Options.
258 */
259 private static class BarostatOptionGroup {
260
261 /**
262 * -p or --npt Specify use of a Monte Carlo Barostat at the given pressure (default 0 = constant
263 * volume).
264 */
265 @Option(names = {"-p", "--npt"}, paramLabel = "0", defaultValue = "0",
266 description = "Specify use of a MC Barostat at the given pressure; the default 0 disables NPT (atm).")
267 private double pressure = 0;
268 /**
269 * -iso or --isotropic Restrict the MC Barostat to isotropic moves. The lattice angles are held
270 * fixed, and lattice lengths are scaled equally.
271 */
272 @Option(names = {"--iso", "--isotropic"},
273 defaultValue = "false", description = "Restrict the MC Barostat to isotropic moves.")
274 private boolean isotropic = false;
275 /**
276 * --maxD or --maxDensity Specify the maximum density accepted by the MC Barostat (g/cc).
277 */
278 @Option(names = {"--maxD", " --maxDensity"},
279 paramLabel = DEFAULT_MAX_DENSITY, defaultValue = DEFAULT_MAX_DENSITY,
280 description = "Specify the maximum density accepted by the MC Barostat (g/cc).")
281 private double maxD = parseDouble(DEFAULT_MAX_DENSITY);
282 /**
283 * --minD or --minDensity Specify the minimum density accepted by the MC Barostat (g/cc).
284 */
285 @Option(names = {"--minD", " --minDensity"},
286 paramLabel = DEFAULT_MIN_DENSITY, defaultValue = DEFAULT_MIN_DENSITY,
287 description = "Specify the minimum density accepted by the MC Barostat (g/cc).")
288 private double minD = parseDouble(DEFAULT_MIN_DENSITY);
289 @Option(names = {"--maxAM", "--maxAngleMove"},
290 paramLabel = DEFAULT_MAX_ANGLE_MOVE, defaultValue = DEFAULT_MAX_ANGLE_MOVE,
291 description = "Sets the width of proposed crystal angle moves (uniformly distributed) in degrees.")
292 private double maxAM = parseDouble(DEFAULT_MAX_ANGLE_MOVE);
293 /**
294 * --maxV or --maxVolumeMove Sets the volume move size (uniformly distributed) in Angstroms^3.
295 */
296 @Option(names = {"--maxV", "--maxVolumeMove"},
297 paramLabel = DEFAULT_MAX_VOLUME_MOVE, defaultValue = DEFAULT_MAX_VOLUME_MOVE,
298 description = "Default width of proposed unit cell side length moves (uniformly distributed) in Angstroms.")
299 private double maxV = parseDouble(DEFAULT_MAX_VOLUME_MOVE);
300
301 /**
302 * --barInt or --meanBarostatInterval Sets the mean number of MD steps (Poisson distribution)
303 * between barostat move proposals.
304 */
305 @Option(names = {"--barInt", "--meanBarostatInterval"},
306 paramLabel = DEFAULT_BAROSTAT_INTERVAL, defaultValue = DEFAULT_BAROSTAT_INTERVAL,
307 description = "Sets the mean number of MD steps between barostat move proposals.")
308 private int barInt = parseInt(DEFAULT_BAROSTAT_INTERVAL);
309 /**
310 * --bpi or --barostatPrintInterval Sets the number of Barostat MC cycles between print
311 * statements.
312 */
313 @Option(names = {"--bpi", "--barostatPrintInterval"},
314 paramLabel = DEFAULT_BAROSTAT_PRINT_INTERVAL, defaultValue = DEFAULT_BAROSTAT_PRINT_INTERVAL,
315 description = "Sets the number of Barostat MC cycles between print statements.")
316 private int barPrint = parseInt(DEFAULT_BAROSTAT_PRINT_INTERVAL);
317 }
318 }