coordinates) {
36 | this.frequency = frequency;
37 | this.reducedMass = reducedMass;
38 | this.forceConstant = forceConstant;
39 |
40 | if ( coordinates == null || coordinates.size() == 0 )
41 | throw new NullPointerException("no normal coordinates");
42 | this.coordinates = ImmutableList.copyOf(coordinates);
43 | }
44 |
45 | @Override
46 | public String toString() {
47 | StringBuilder s = new StringBuilder(String.format("\nFrequency (cm-1): %.2f\n", frequency));
48 | s.append(String.format("Reduced Mass (amu): %.2f\n", reducedMass));
49 | s.append(String.format("Force Constant (mDyne/A): %.2f\n",forceConstant));
50 | s.append("Normal Coordinates (xyz; A):\nAtom Index: X displacement: Y displacement Z displacement:\n");
51 | for (int i=0; i < coordinates.size(); i++)
52 | {
53 | Vector3D v = coordinates.get(i);
54 | s.append(String.format("%5d %10.5f %10.5f %10.5f\n", (i+1), v.getX(), v.getY(), v.getZ()));
55 | }
56 | s.append("\n");
57 | return s.toString();
58 | }
59 |
60 | @Override
61 | public int hashCode() {
62 | return Objects.hash(frequency, reducedMass, forceConstant, coordinates);
63 | }
64 |
65 | @Override
66 | public boolean equals(Object obj) {
67 | if ( obj == null )
68 | return false;
69 | if ( obj == this )
70 | return true;
71 | if ( !(obj instanceof NormalMode) )
72 | return false;
73 |
74 | NormalMode n = (NormalMode)obj;
75 | if ( frequency == n.frequency &&
76 | reducedMass == n.reducedMass &&
77 | forceConstant == n.forceConstant &&
78 | coordinates.equals(coordinates) )
79 | return true;
80 | return false;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/edu/harvard/chemistry/ekwan/Jprogdyn/OutputFileFormat.java:
--------------------------------------------------------------------------------
1 | package edu.harvard.chemistry.ekwan.Jprogdyn;
2 |
3 | import java.io.*;
4 | import java.util.*;
5 | import com.google.common.collect.*;
6 |
7 | /**
8 | * This abstract class represents the result of a program external to Jprogdyn.
9 | */
10 | public abstract class OutputFileFormat implements FileFormat
11 | {
12 |
13 | /**
14 | * The raw text in the file.
15 | */
16 | public final String stringRepresentation;
17 |
18 | /**
19 | * The parsed contents of the file.
20 | * The outer list contains each line.
21 | * Each inner list contains the space-separated tokens for each line.
22 | */
23 | public final List> fileContents;
24 |
25 | /**
26 | * Constructor.
27 | * @param stringRepresentation the raw text in the file
28 | * @param fileContents the parsed contents of the file (outer list contains each line, inner list contains space-separated tokens)
29 | */
30 | public OutputFileFormat(String stringRepresentation, List> fileContents) {
31 | this.stringRepresentation = stringRepresentation;
32 | this.fileContents = fileContents;
33 | }
34 |
35 | /**
36 | * Constructs an instance by reading text from filename.
37 | * Fields are parsed by using spaces as delimeters. Consecutive delimiters are ignored.
38 | * @param filename the file to read from
39 | */
40 | public OutputFileFormat(String filename) {
41 | // get file length
42 | File file = new File(filename);
43 | long length = file.length(); // in bytes
44 | int characters = (int)(length/2L);
45 |
46 | List> tempList = new LinkedList<>();
47 | StringBuilder builder = new StringBuilder(characters);
48 | String line = null;
49 | try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
50 | while ( (line = reader.readLine()) != null )
51 | {
52 | line = line.trim();
53 | String[] fields = line.split("\\s+");
54 | tempList.add(ImmutableList.copyOf(fields));
55 | builder.append(line);
56 | builder.append("\n");
57 | }
58 | }
59 | catch (Exception e) {
60 | throw new IllegalArgumentException(e.getMessage());
61 | }
62 | stringRepresentation = builder.toString();
63 | fileContents = ImmutableList.copyOf(tempList);
64 | }
65 |
66 | /**
67 | * Return the contents of the file. Newlines will be present.
68 | * @return the text that was in the file
69 | */
70 | @Override
71 | public String toString() {
72 | return stringRepresentation;
73 | }
74 |
75 | @Override
76 | public int hashCode() {
77 | return Objects.hash(stringRepresentation, fileContents);
78 | }
79 |
80 | @Override
81 | public boolean equals(Object obj) {
82 | if ( obj == null )
83 | return false;
84 | if ( obj == this )
85 | return true;
86 | if ( !(obj instanceof OutputFileFormat) )
87 | return false;
88 |
89 | OutputFileFormat o = (OutputFileFormat)obj;
90 | if ( stringRepresentation.equals(o.stringRepresentation) &&
91 | fileContents.equals(o.fileContents) )
92 | return true;
93 | return false;
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/edu/harvard/chemistry/ekwan/Jprogdyn/Propagator.java:
--------------------------------------------------------------------------------
1 | package edu.harvard.chemistry.ekwan.Jprogdyn;
2 |
3 | /**
4 | * This interface represents an object that calculates the next or previous trajectory point.
5 | */
6 | public interface Propagator {
7 | /**
8 | * Calculates the next trajectory point.
9 | * @param trajectory the trajectory being propagated
10 | * @param point the last point
11 | * @param forwards whether to go forwards (true) or backwards (false)
12 | * @param isNMRpoint whether NMR shieldings should be evaluated for the next point
13 | * @return the next point
14 | */
15 | public TrajectoryPoint propagate(Trajectory trajectory, TrajectoryPoint point, boolean forwards, boolean isNMRpoint);
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/edu/harvard/chemistry/ekwan/Jprogdyn/Propagators.java:
--------------------------------------------------------------------------------
1 | package edu.harvard.chemistry.ekwan.Jprogdyn;
2 |
3 | import java.util.*;
4 | import org.apache.commons.math3.geometry.euclidean.threed.*;
5 |
6 | /**
7 | * This enum contains implementations of Propagator.
8 | * Only the Velocity Verlet algorithm is currently implemented.
9 | */
10 | public enum Propagators implements Propagator {
11 | /**
12 | * Uses the velocity Verlet algorithm to calculate the next point. The algorithm is:
13 | *
14 | * x(t + Dt) = x(t) + v(t) * Dt + 0.5 * a(t) * Dt^2
15 | * v(t + Dt) = v(t) + 0.5 * [ a(t) + a(t+Dt) ] Dt
16 | *
17 | * where Dt is the timestep, x(t) is the position at time t, v(t) is the velocity at time t, and
18 | * a(t) is the acceleration at time t. The acceleration can be derived from the force divided by the mass.
19 | * Unlike the regular Verlet, this algorithm is self-starting.
20 | *
21 | * Note that because we need the accelerations from both points to calculate the new velocity, we have to
22 | * make an intermediate TrajectoryPoint that only has the new positions. This intermediate is not exposed.
23 | */
24 | VELOCITY_VERLET {
25 | @Override
26 | public TrajectoryPoint propagate(Trajectory trajectory, TrajectoryPoint oldPoint, boolean forwards, boolean isNMRpoint) {
27 | // check for nulls
28 | if (trajectory == null)
29 | throw new NullPointerException("null trajectory");
30 | if (oldPoint == null)
31 | throw new NullPointerException("null old point");
32 |
33 | // get required information
34 | Molecule molecule = trajectory.molecule;
35 | CalculationMethod dynamicsMethod = trajectory.dynamicsMethod;
36 | CalculationMethod nmrMethod = trajectory.nmrMethod;
37 |
38 | // set timestep
39 | double timestep = trajectory.timestep; // in fs
40 | if ( timestep < 0.0 )
41 | throw new IllegalArgumentException("timestep must be positive");
42 | if ( ! forwards )
43 | timestep = timestep * -1.0; // go backwards
44 |
45 | // initialize lists to hold new verlet quantities
46 | List x_t = oldPoint.positions; // current positions in angstroms
47 | List v_t = oldPoint.velocities; // current velocities in angstroms/femtosecond
48 | List a_t = oldPoint.forces2; // 1/2 * a * Dt^2 in angstroms
49 |
50 | // calculate new positions
51 | List x_t_plus = new ArrayList(x_t);
52 | for (int i=0; i < x_t_plus.size(); i++) {
53 | Vector3D v = x_t_plus.get(i);
54 | v = v.add( v_t.get(i).scalarMultiply(timestep) );
55 | v = v.add( a_t.get(i) );
56 | x_t_plus.set(i, v);
57 | Vector3D delta = v.subtract(x_t.get(i));
58 | }
59 |
60 | // evaluate forces with new geometry
61 | TrajectoryPoint tempPoint = TrajectoryPoint.create(oldPoint.time + timestep, x_t_plus);
62 | if ( isNMRpoint )
63 | tempPoint = tempPoint.evaluatePoint(molecule, nmrMethod, timestep);
64 | else
65 | tempPoint = tempPoint.evaluatePoint(molecule, dynamicsMethod, timestep);
66 |
67 | // get accelerations in A/s^2
68 | List oldAccelerations = oldPoint.accelerations;
69 | List newAccelerations = tempPoint.accelerations;
70 |
71 | // calculate new velocities
72 | List v_t_plus = new ArrayList(v_t);
73 | for (int i=0; i < v_t_plus.size(); i++)
74 | {
75 | Vector3D v = v_t_plus.get(i);
76 | Vector3D temp = oldAccelerations.get(i).add( newAccelerations.get(i) );
77 | temp = temp.scalarMultiply(0.5 * timestep);
78 | v = v.add(temp);
79 | v_t_plus.set(i, v);
80 | }
81 |
82 | // calculate kinetic and total energies
83 | // dimensional analysis:
84 | //
85 | // g A^2 fs^2 1E-20 m^2 kg s^2 J hartree
86 | // ----- * -------- * ---------------------- * ----------- * --------- * -------- * ----------------- = hartree
87 | // mol fs^2 1E-30 s^2 A^2 1000 g kg m^2 J_PER_HARTREE J
88 | //
89 | // = 1E7 / J_PER_HARTREE * timestep^2
90 | double kineticEnergy = 0.0; // in hartree / mol
91 | double conversionFactor = 1E7 / ( Units.J_PER_HARTREE * timestep * timestep );
92 | for (int i=0; i < molecule.contents.size(); i++)
93 | {
94 | double mass = molecule.contents.get(i).mass; // amu
95 | double velocityNorm = v_t_plus.get(i).getNormSq(); // (A/fs)^2
96 | kineticEnergy += 0.5 * mass * velocityNorm * conversionFactor; // 0.5 * m * v^2
97 | }
98 | double totalEnergy = kineticEnergy + tempPoint.potentialEnergy; // in hartree
99 |
100 | // construct and return new point
101 | return new TrajectoryPoint(tempPoint.time, kineticEnergy, tempPoint.potentialEnergy, totalEnergy,
102 | tempPoint.positions, v_t_plus, tempPoint.accelerations, tempPoint.forces,
103 | tempPoint.forces2, tempPoint.shieldings, tempPoint.evaluationTime);
104 | }
105 | };
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/edu/harvard/chemistry/ekwan/Jprogdyn/RotationalBoltzmann.java:
--------------------------------------------------------------------------------
1 | package edu.harvard.chemistry.ekwan.Jprogdyn;
2 |
3 | import org.apache.commons.math3.geometry.euclidean.threed.*;
4 | import org.apache.commons.math3.linear.*;
5 | import org.apache.commons.math3.special.*;
6 | import com.google.common.collect.*;
7 | import java.util.*;
8 | import java.io.*;
9 | import java.util.concurrent.*;
10 |
11 | /**
12 | * A Boltzmann-like distribution of angular momenta for a given molecule.
13 | * This object should be initialized using a list of Atoms, and
14 | * will calculate and store the principal axes, inertia tensor,
15 | * and parameters for a distribution of angular frequency vectors. When the
16 | * getRotation method is called, an angular frequency vector
17 | * is obtained from random distribution.
18 | */
19 | public class RotationalBoltzmann implements Immutable {
20 | /**
21 | * Multiplication by this constant converts amu * angstrom^2
22 | * to electronVolt * femtosecond^2. Believe it or not, this is
23 | * the only unit conversion factor required, as the Boltzmann
24 | * distribution is calculated in terms of a unitless parameter.
25 | */
26 | private final static double MAGIC_CONSTANT = 103.642692;
27 |
28 | /** Principal axes. */
29 | public final Vector3D axis1, axis2, axis3;
30 |
31 | /** Principal moments in amu * angstrom^2 */
32 | public final double I1, I2, I3;
33 |
34 | /**
35 | * Constructs the distribution from a Molecule.
36 | * @param molecule the input molecule
37 | */
38 | public RotationalBoltzmann(Molecule molecule) {
39 | this(molecule.contents);
40 | }
41 |
42 | /**
43 | * Constructs the distribution from a list of atoms.
44 | * @param contents the molecular geometry to build the distribution from
45 | */
46 | public RotationalBoltzmann(List contents)
47 | {
48 | // we want to move the center of mass to the origin for easy calculation
49 | Vector3D centerOfMass = RotationalBoltzmann.centerOfMass(contents);
50 | List shiftedContents = new ArrayList();
51 | for ( Atom atom : contents ) {
52 | Vector3D oldPosition = atom.position;
53 | Vector3D translation = centerOfMass.negate();
54 | Vector3D newPosition = oldPosition.add(translation);
55 | Atom newAtom = atom.shift(newPosition);
56 | shiftedContents.add(newAtom);
57 | }
58 |
59 | // we will now calculate moments
60 | double Ixx = 0;
61 | double Iyy = 0;
62 | double Izz = 0;
63 | double Ixy = 0;
64 | double Iyz = 0;
65 | double Ixz = 0;
66 | for ( Atom atom : shiftedContents )
67 | {
68 | if ( atom.mass == 0 )
69 | throw new IllegalArgumentException("Atom mass is zero!");
70 |
71 | Ixx += atom.mass * (atom.position.getY()*atom.position.getY() + atom.position.getZ()*atom.position.getZ());
72 | Iyy += atom.mass * (atom.position.getX()*atom.position.getX() + atom.position.getZ()*atom.position.getZ());
73 | Izz += atom.mass * (atom.position.getX()*atom.position.getX() + atom.position.getY()*atom.position.getY());
74 | Ixy -= atom.mass * atom.position.getX() * atom.position.getY();
75 | Iyz -= atom.mass * atom.position.getY() * atom.position.getZ();
76 | Ixz -= atom.mass * atom.position.getX() * atom.position.getZ();
77 | }
78 |
79 | RealMatrix I = MatrixUtils.createRealMatrix(new double[][]{{Ixx, Ixy, Ixz},{Ixy, Iyy, Iyz},{Ixz, Iyz, Izz}});
80 |
81 | EigenDecomposition eigenI = new EigenDecomposition(I);
82 |
83 | // get the principal axes from the V matrix
84 | this.axis1 = new Vector3D(eigenI.getV().getColumn(0)).normalize();
85 | this.axis2 = new Vector3D(eigenI.getV().getColumn(1)).normalize();
86 | this.axis3 = new Vector3D(eigenI.getV().getColumn(2)).normalize();
87 |
88 | // read the eigenvalues from the EigenDecomposition.
89 | // certain pathological cases will not have three eigenvalues
90 | // in this cases, we will store a zero value for some eigenvalues,
91 | // and remember to deal with it when obtaining an angular frequency.
92 | // essentially, we will not rotate on axes with zero eigenvalue.
93 | double[] evalues = eigenI.getRealEigenvalues();
94 |
95 | if ( evalues.length == 0 )
96 | throw new IllegalArgumentException ("Given atom group has no valid rotations!");
97 | else if ( evalues.length == 1 )
98 | {// This case is silly, and will never occur.
99 | I1 = evalues[0];
100 | I2 = 0;
101 | I3 = 0;
102 | }
103 | else if ( evalues.length == 2 )
104 | {// This is the linear case.
105 | I1 = evalues[0];
106 | I2 = evalues[1];
107 | I3 = 0;
108 | }
109 | else
110 | {
111 | I1 = evalues[0];
112 | I2 = evalues[1];
113 | I3 = evalues[2];
114 | }
115 | }
116 |
117 | /**
118 | * Returns a random angular frequency from the distribution. The user
119 | * inputs a temperature, and three random numbers. These numbers correspond
120 | * to the rotational energy around each of the 3 principal axes. The sign
121 | * of the number specifies the direction, while the magnitude of the number
122 | * represents the fraction of molecules that should have less rotational
123 | * energy in this mode in our distribution. The returned angular momentum
124 | * is in regular Cartesian coordinates -- anyone outside this class
125 | * should not have to think about the principal axes.
126 | * @param kT a double representing the temperature in ELECTRONVOLTS
127 | * @param x1 a random number between -1 and 1 for the first angular frequency component
128 | * @param x2 a random number between -1 and 1 for the second angular frequency component
129 | * @param x3 a random number between -1 and 1 for the third angular frequency component
130 | * @return omega, the angular frequency in radians per FEMTOSECOND
131 | */
132 | public Vector3D getOmega(double kT, double x1, double x2, double x3)
133 | {
134 | double[] omega = {0,0,0};
135 | // we remove the signs and put them back later
136 | int sign1 = (int)Math.signum(x1);
137 | int sign2 = (int)Math.signum(x2);
138 | int sign3 = (int)Math.signum(x3);
139 | x1 = Math.abs(x1);
140 | x2 = Math.abs(x2);
141 | x3 = Math.abs(x3);
142 | double energy1 = 0;
143 | double energy2 = 0;
144 | double energy3 = 0;
145 |
146 | if (I1 > 0)
147 | {
148 | energy1 = kT * inverseCumulativeBoltzmann(x1);
149 | omega[0] = sign1 * Math.sqrt((2 * energy1)/(I1 * MAGIC_CONSTANT));
150 | }
151 | if (I2 > 0)
152 | {
153 | energy2 = kT * inverseCumulativeBoltzmann(x2);
154 | omega[1] = sign2 * Math.sqrt((2 * energy2)/(I2 * MAGIC_CONSTANT));
155 | }
156 | if (I3 > 0)
157 | {
158 | energy3 = kT * inverseCumulativeBoltzmann(x3);
159 | omega[2] = sign3 * Math.sqrt((2 * energy3)/(I1 * MAGIC_CONSTANT));
160 | }
161 |
162 | double conversion = 3.8267327959301E-23 * Units.AVOGADROS_NUMBER;
163 | double energy1_kcal = energy1 * conversion;
164 | double energy2_kcal = energy2 * conversion;
165 | double energy3_kcal = energy3 * conversion;
166 | double totalEnergy_kcal = energy1_kcal + energy2_kcal + energy3_kcal;
167 | //System.out.printf("Total rotational energy: %.4f kcal/mol (%.4f axis1, %.4f axis2, %.4f axis3)\n", totalEnergy_kcal, energy1_kcal, energy2_kcal, energy3_kcal);
168 |
169 | // transform these back into regular Cartesian coordinates
170 | return new Vector3D(omega[0], axis1, omega[1], axis2, omega[2], axis3);
171 | }
172 |
173 | /**
174 | * Calculates the center of mass vector for a list of atoms.
175 | */
176 | private static Vector3D centerOfMass(List contents)
177 | {
178 | double totalMass = 0.0;
179 | Vector3D weightedPosition = Vector3D.ZERO;
180 | for ( Atom atom : contents )
181 | {
182 | totalMass += atom.mass;
183 | weightedPosition = weightedPosition.add(atom.mass, atom.position);
184 | }
185 | return weightedPosition.scalarMultiply(1.0/totalMass);
186 | }
187 |
188 | /**
189 | * Returns a random energy drawn from a Boltzmann distribution for the specified temperature.
190 | * Will return a mean energy of 0.5 kT. 0.5 kT is about 0.3 kcal/mol at 298 K.
191 | * @param temperature the temperature in K
192 | * @return the random energy in kcal/mol
193 | */
194 | public static double getRandomBoltzmannEnergy(double temperature)
195 | {
196 | double randomNumber = ThreadLocalRandom.current().nextDouble();
197 |
198 | //
199 | // kcal
200 | // ------- * K = kcal/mol ---> must use R, not k
201 | // mol K
202 | //
203 | double kT = Units.R_GAS_KCAL * temperature;
204 | double energy = inverseCumulativeBoltzmann(randomNumber) * kT;
205 | return energy;
206 | }
207 |
208 | /** How many kT to search up to. */
209 | public static final double CUTOFF_ENERGY = 10.0;
210 |
211 | /**
212 | * Inverse Cumulative Boltzmann helper method. Calculates the
213 | * rotational kinetic energy for which x fraction of molecules have less
214 | * kinetic energy. Normalized so that kT = 1.
215 | * Unit conversions are to be made outside the method.
216 | * @param x the fraction of molecules with less rotational energy
217 | * @return energy divided by kT
218 | */
219 | private static double inverseCumulativeBoltzmann(double x)
220 | {
221 | if (x > 1 || x < 0)
222 | throw new IllegalArgumentException("Illegal rotational energy specification.");
223 |
224 | // Find the inverse of this monotonically increasing function
225 | // in two steps. First scan up to 10 kT with large tolerance,
226 | // then scan in smaller steps around the solution. The cutoff at 10 kT
227 | // is arbitrary, but we should not be using energies that high anyway.
228 | double trialEnergy = -1;
229 | for ( double i = 0; i < CUTOFF_ENERGY; i += 0.01 )
230 | {
231 | if ( cumulativeBoltzmann(i) > x )
232 | {
233 | trialEnergy = i - 0.01;
234 | break;
235 | }
236 | // System.out.println( cumulativeBoltzmann(i) );
237 | }
238 |
239 | // if we failed to find the inverse on this first pass,
240 | // we are in the high energy tail of the distribution, and
241 | // we simply return the max energy
242 | if ( trialEnergy == -1 )
243 | return CUTOFF_ENERGY;
244 |
245 | // now we scan in small steps.
246 | for ( double i = trialEnergy; i < trialEnergy + 0.01; i += 0.0001 )
247 | {
248 | if ( cumulativeBoltzmann(i) > x )
249 | {
250 | trialEnergy = i - 0.00001;
251 | break;
252 | }
253 | }
254 | return trialEnergy - 0.00001;
255 | }
256 |
257 | /**
258 | * Cumulative Boltzmann helper method. Calculates the cumulative
259 | * Boltzmann distribution for a positive energy x = E/kT.
260 | * @param x the energy
261 | * @return the probability of a molecule having kinetic energy less than x
262 | */
263 | private static double cumulativeBoltzmann(double x)
264 | {
265 | if ( x < 0 )
266 | throw new IllegalArgumentException("Tried to use Boltzmann cdf with negative energy!");
267 | return Erf.erf(Math.sqrt(x)); // Kinetic energy is normally distributed.
268 |
269 | //return Math.sqrt(x)*(-2*Math.exp(-x)/Math.sqrt(Math.PI) + Erf.erf(Math.sqrt(x))/Math.sqrt(x));
270 | }
271 |
272 | /**
273 | * This is a static utility method that calculates velocities for rotation.
274 | * Given a group of atoms and an origin, the method should return a matching
275 | * List of velocities for these atoms that performs a rotation at angular
276 | * frequency omega.
277 | * @param contents a list of atoms to be rotated
278 | * @param omega the angular frequency vector in radians per FEMTOSECOND
279 | * @param origin the origin of rotation; it is recommended that
280 | * this be set to the origin of the coordinate system
281 | * so that center of mass rotations will not be confused
282 | * with other rotations. See alias methods.
283 | * @return vector of velocities in the same order as the original
284 | */
285 | public static List getVelocities(List contents, Vector3D omega, Vector3D origin)
286 | {
287 | List shiftedContents = new ArrayList();
288 | for ( Atom atom : contents )
289 | shiftedContents.add(atom.shift(origin.negate()));
290 |
291 | List returnList = new ArrayList<>(contents.size());
292 | for ( Atom atom : contents )
293 | returnList.add(Vector3D.crossProduct(omega, atom.position));
294 |
295 | return ImmutableList.copyOf(returnList);
296 | }
297 |
298 | /**
299 | * Alias method. Automatically use center of mass as rotation origin.
300 | * @param contents the molecular geometry
301 | * @param omega the angular frequency vector
302 | * @return vector of velocities in same order as the original
303 | */
304 | public static List getVelocities(List contents, Vector3D omega) {
305 | return getVelocities(contents, omega, RotationalBoltzmann.centerOfMass(contents));
306 | }
307 |
308 | /**
309 | * Checks equality by checking the contained atoms only.
310 | */
311 | @Override
312 | public boolean equals(Object obj) {
313 | if ( obj == null )
314 | return false;
315 | if ( obj == this )
316 | return true;
317 | if ( !(obj instanceof RotationalBoltzmann) )
318 | return false;
319 |
320 | RotationalBoltzmann r = (RotationalBoltzmann)obj;
321 | if ( axis1.equals(r.axis1) &&
322 | axis2.equals(r.axis2) &&
323 | axis3.equals(r.axis3) &&
324 | I1 == r.I1 &&
325 | I2 == r.I2 &&
326 | I3 == r.I3 )
327 | return true;
328 | return false;
329 | }
330 |
331 | /**
332 | * String representation of the distribution is just the axes and moments.
333 | */
334 | @Override
335 | public String toString() {
336 | return(I1 + "\n" + axis1 + "\n"
337 | + I2 + "\n" + axis2 + "\n"
338 | + I3 + "\n" + axis3 + "\n");
339 | }
340 |
341 | /**
342 | * To agree with this.equals, the hash is just that of the atoms.
343 | */
344 | public int hashCode() {
345 | return Objects.hash(axis1, axis2, axis3, I1, I2, I3);
346 | }
347 | }
348 |
--------------------------------------------------------------------------------
/src/main/java/edu/harvard/chemistry/ekwan/Jprogdyn/Singleton.java:
--------------------------------------------------------------------------------
1 | package edu.harvard.chemistry.ekwan.Jprogdyn;
2 |
3 | /**
4 | * This is a marker interface for classes that must exist as singletons.
5 | */
6 | public interface Singleton {
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/edu/harvard/chemistry/ekwan/Jprogdyn/TrajectoryExecutorService.java:
--------------------------------------------------------------------------------
1 | package edu.harvard.chemistry.ekwan.Jprogdyn;
2 |
3 | import java.util.*;
4 | import java.io.*;
5 | import java.util.concurrent.*;
6 |
7 | /**
8 | * This class provides static methods to run groups of Trajectories.
9 | */
10 | public class TrajectoryExecutorService implements Singleton {
11 |
12 | /** Thread pool for doing the work. */
13 | private static final ThreadPoolExecutor EXECUTOR;
14 |
15 | /** Static initializer. */
16 | static {
17 | ArrayBlockingQueue queue = new ArrayBlockingQueue<>(100000, true); // fair queue
18 | int NUMBER_OF_THREADS = Loader.getInteger("number_of_simultaneous_trajectories");
19 | EXECUTOR = new ThreadPoolExecutor(NUMBER_OF_THREADS, NUMBER_OF_THREADS, Long.MAX_VALUE, TimeUnit.SECONDS, queue);
20 | }
21 |
22 | /** Not instantiable. */
23 | private TrajectoryExecutorService() {
24 | throw new IllegalArgumentException("not instantiable");
25 | }
26 |
27 | /**
28 | * Runs a group of trajectories in parallel.
29 | * The calling thread blocks until the trajectories are finished.
30 | * If there is a problem running any of the trajectories, the original trajectory is returned.
31 | * @param trajectories the trajectories to run
32 | * @return the completed trajectories
33 | */
34 | public static List runTrajectories(List trajectories) {
35 | if ( trajectories == null )
36 | throw new NullPointerException("trajectories is null");
37 |
38 | // submit work
39 | System.out.printf("Running %d trajectories...\n", trajectories.size());
40 | List> futures = new LinkedList<>();
41 | for (Trajectory t : trajectories) {
42 | Future f = EXECUTOR.submit(t);
43 | futures.add(f);
44 | }
45 |
46 | // wait until jobs are done
47 | while (true) {
48 | int done = 0;
49 | for (Future f : futures) {
50 | if ( f.isDone() || f.isCancelled() )
51 | done++;
52 | }
53 | if ( done == futures.size() )
54 | break;
55 | try { Thread.sleep(500); }
56 | catch ( InterruptedException e ) {}
57 | }
58 |
59 | // return result
60 | List completedTrajectories = new LinkedList<>();
61 | for (int i=0; i < trajectories.size(); i++) {
62 | Trajectory originalTrajectory = trajectories.get(i);
63 | Trajectory finishedTrajectory = null;
64 | Future f = futures.get(i);
65 | try { finishedTrajectory = f.get(); }
66 | catch (Exception e) { }
67 | if ( finishedTrajectory != null )
68 | completedTrajectories.add(finishedTrajectory);
69 | else
70 | completedTrajectories.add(originalTrajectory);
71 | }
72 | return completedTrajectories;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/edu/harvard/chemistry/ekwan/Jprogdyn/TrajectoryPoint.java:
--------------------------------------------------------------------------------
1 | package edu.harvard.chemistry.ekwan.Jprogdyn;
2 |
3 | import org.apache.commons.math3.geometry.euclidean.threed.*;
4 | import java.util.*;
5 | import java.io.*;
6 | import com.google.common.collect.*;
7 |
8 | /**
9 | * This class represents a point along a molecular dynamics trajectory.
10 | */
11 | public class TrajectoryPoint implements Immutable, Serializable {
12 |
13 | /** For serialization. */
14 | public static final long serialVersionUID = 1L;
15 |
16 | /** The time in fs. Can be negative for backwards points. */
17 | public final double time;
18 |
19 | /** The kinetic energy in hartree. */
20 | public final double kineticEnergy;
21 |
22 | /** The potential energy in hartree. */
23 | public final double potentialEnergy;
24 |
25 | /** The total energy in kcal. */
26 | public final double totalEnergy;
27 |
28 | /** The current positions of all atoms in A. */
29 | public final List positions;
30 |
31 | /** Cartesian velocities of all the atoms in angstroms/femtosecond. */
32 | public final List velocities;
33 |
34 | /** Cartesian accelerations of all atoms in angstroms/fs^2. */
35 | public final List accelerations;
36 |
37 | /** Cartesian forces on all atoms in hartrees/bohr. */
38 | public final List forces;
39 |
40 | /** Cartesian forces on all atoms in (1/2 acceleration timeStep^2 term) in angstroms. */
41 | public final List forces2;
42 |
43 | /** Absolute NMR shieldings in ppm. */
44 | public final List shieldings;
45 |
46 | /** Time it took to evaluate this point in seconds. */
47 | public final double evaluationTime;
48 |
49 | /**
50 | * Constructs a TrajectoryPoint.
51 | * @param time the time in fs (negative for backwards points)
52 | * @param kineticEnergy the kinetic energy in hartree
53 | * @param potentialEnergy the potential energy in hartree
54 | * @param totalEnergy the total energy in kcal
55 | * @param positions the positions of all atoms in Angstroms (cannot be null)
56 | * @param velocities Cartesian velocities of all the atoms in angstroms/femtosecond
57 | * @param accelerations accelerations of all atoms in angstroms/fs^2
58 | * @param forces Cartesian forces on all atoms in hartrees/bohr
59 | * @param forces2 Cartesian forces on all atoms in (1/2 acceleration timeStep^2 term) in angstroms
60 | * @param shieldings absolute NMR shieldings in ppm
61 | * @param evaluationTime time it took to evaluate this point in seconds
62 | */
63 | public TrajectoryPoint(double time, double kineticEnergy, double potentialEnergy, double totalEnergy,
64 | List positions, List velocities, List accelerations,
65 | List forces, List forces2, List shieldings,
66 | double evaluationTime) {
67 |
68 | // check invariants
69 | this.time = time;
70 |
71 | if ( kineticEnergy < 0.0 )
72 | throw new IllegalArgumentException("negative kinetic energy");
73 | this.kineticEnergy = kineticEnergy;
74 |
75 | this.potentialEnergy = potentialEnergy;
76 | this.totalEnergy = totalEnergy;
77 |
78 | if ( positions == null || positions.size() == 0 )
79 | throw new NullPointerException("null positions");
80 | this.positions = ImmutableList.copyOf(positions);
81 |
82 | if ( velocities == null )
83 | this.velocities = null;
84 | else {
85 | if ( velocities.size() == 0 )
86 | throw new IllegalArgumentException("empty velocities");
87 | this.velocities = ImmutableList.copyOf(velocities);
88 | }
89 |
90 | if ( accelerations == null )
91 | this.accelerations = null;
92 | else {
93 | if ( accelerations.size() == 0 )
94 | throw new IllegalArgumentException("empty accelerations");
95 | this.accelerations = ImmutableList.copyOf(accelerations);
96 | }
97 |
98 | if ( forces == null )
99 | this.forces = null;
100 | else {
101 | if ( forces.size() == 0 )
102 | throw new IllegalArgumentException("empty forces");
103 | this.forces = ImmutableList.copyOf(forces);
104 | }
105 |
106 | if ( forces2 == null )
107 | this.forces2 = null;
108 | else {
109 | if ( forces2.size() == 0 )
110 | throw new IllegalArgumentException("empty forces2");
111 | this.forces2 = ImmutableList.copyOf(forces2);
112 | }
113 |
114 | if ( shieldings == null )
115 | this.shieldings = null;
116 | else
117 | this.shieldings = ImmutableList.copyOf(shieldings);
118 |
119 | if (evaluationTime < 0.0)
120 | throw new IllegalArgumentException("negative evaluation time");
121 | this.evaluationTime = evaluationTime;
122 | }
123 |
124 | /**
125 | * Makes a trajectory point but does not evaluate it. Created with time and positions only.
126 | * @param time the time in fs (negative for backwards points)
127 | * @param positions the current positions of all atoms in Angstroms
128 | * @return a blank TrajectoryPoint
129 | */
130 | public static TrajectoryPoint create(double time, List positions) {
131 | return new TrajectoryPoint(time, 0.0, 0.0, 0.0, positions, null, null, null, null, null, 0.0);
132 | }
133 |
134 | /**
135 | * Makes a trajectory point but does not evaluate it. Created with time, positions, and velocities only.
136 | * @param time the time in fs (negative for backwards points)
137 | * @param positions the current positions of all atoms in Angstroms
138 | * @param velocities Cartesian velocities of all the atoms in angstroms/femtosecond
139 | * @return a blank TrajectoryPoint
140 | */
141 | public static TrajectoryPoint create(double time, List positions, List velocities) {
142 | return new TrajectoryPoint(time, 0.0, 0.0, 0.0, positions, velocities, null, null, null, null, 0.0);
143 | }
144 |
145 | /**
146 | * Evaluates the point and returns a replacement that has all the fields all filled out.
147 | * @param molecule needed for header information
148 | * @param calculationMethod level of theory
149 | * @param timestep the timestep between the last point and this point in fs
150 | * @return the evaluated point
151 | */
152 | public TrajectoryPoint evaluatePoint(Molecule molecule, CalculationMethod calculationMethod, double timestep) {
153 | if ( calculationMethod == null )
154 | throw new NullPointerException("must specify a calculation method!");
155 | if ( calculationMethod instanceof GaussianCalculationMethod )
156 | return evaluateGaussianPoint(molecule, (GaussianCalculationMethod)calculationMethod, timestep);
157 | else
158 | throw new IllegalArgumentException("unrecognized electronic structure program");
159 | }
160 |
161 | /**
162 | * Evaluates a TrajectoryPoint using Gaussian.
163 | * @param molecule needed for header information
164 | * @param gaussianCalculationMethod level of theory
165 | * @param timestep the timestep between the last point and this point in fs
166 | * @return the evaluated point
167 | */
168 | private TrajectoryPoint evaluateGaussianPoint(Molecule molecule, GaussianCalculationMethod gaussianCalculationMethod, double timestep) {
169 | // create and run job
170 | GaussianInputFile inputFile = new GaussianInputFile(molecule, positions, gaussianCalculationMethod);
171 | GaussianJob job = new GaussianJob(inputFile);
172 | GaussianResult result = job.call();
173 | GaussianOutputFile outputFile = result.out;
174 | Molecule m = outputFile.molecule;
175 |
176 | // If available, change from forces, which is in hartree/bohr, to forces2, which is in Angstroms. forces2 is defined as a distance in angstroms:
177 | //
178 | // 0.5 * acceleration * timestep^2 term
179 | //
180 | // This is useful because we need to calculate x(t) = x(0) + velocity(t) * t + 0.5*a*t^2.
181 | // force = mass * acceleration, so divide force by mass to get acceleration and multiply by timestep^2.
182 | //
183 | // Here is the dimensional analysis. Capital letters represent constants in the Units class. Note that a J is kg m^2 s^-2, which cancels
184 | // out the timestep s^2 and the mass kg.
185 | //
186 | // hartree timestep^2 1E-30 s^2 1000 g KCAL_PER_HARTREE kcal 4184 kg 1E20 angstrom^2 bohr
187 | // --------- * ---------------------- * -------- * ----------------------- * -------- -------------------- * ----------------
188 | // bohr mass * g/mol kg hartree kcal s^2 BOHR angstroms
189 | //
190 | // where I replaced J with kg (1E20 angstrom^2) s^-2 in the third last term. Also note that hartree is implicitly energy/mol. The numbers are:
191 | //
192 | // timestep^2 * 1E-30 * 1000 * KCAL_PER_HARTREE * 4184 * 1E20 timestep^2 * 1E-7 * KCAL_PER_HARTREE * 4184
193 | // = ----------------------------------------------------------- = ---------------------------------------------
194 | // mass * BOHR mass * BOHR
195 | //
196 | // The actual conversion factor needs an extra 0.5.
197 | List newForces = m.forces; // hartree/bohr
198 | List newForces2 = null; // in angstroms
199 | List newAccelerations = null; // in A / fs^2
200 | if ( newForces != null ) {
201 | if ( newForces.size() != molecule.contents.size() )
202 | throw new IllegalArgumentException("list size mismatch: check that forces were calculated");
203 |
204 | // calculate 0.5 * a * t^2 term
205 | newForces2 = new ArrayList<>(newForces.size());
206 | double conversionFactor = 0.5 * timestep * timestep * 1E-7 * Units.KCAL_PER_HARTREE * 4184 / Units.BOHR;
207 | for (int i=0; i < molecule.contents.size(); i++) {
208 | Vector3D rawForce = newForces.get(i);
209 | double mass = molecule.contents.get(i).mass; // in amu
210 | Vector3D newForce = rawForce.scalarMultiply(conversionFactor/mass);
211 | newForces2.add(newForce);
212 | }
213 |
214 | // calculate accelerations in A / fs^2
215 | //
216 | // force = mass * acceleration, so divide force by mass to get acceleration
217 | //
218 | // dimensional analysis:
219 | //
220 | // hartree mol bohr 1000 g J_PER_HARTREE J kg m^2 1 1E20 A^2 1E-30 s^2
221 | // --------- * ----- * ---------------- * -------- * ----------------- * -------- --- * ---------- * -----------
222 | // bohr g BOHR angstroms kg hartree s^2 J m^2 fs^2
223 | //
224 | // = 1000 * J_PER_HARTREE * 1E-10 / BOHR
225 | newAccelerations = new ArrayList<>(newForces.size());
226 | conversionFactor = 1E-7 * Units.J_PER_HARTREE / Units.BOHR;
227 | for (int i=0; i < molecule.contents.size(); i++) {
228 | Vector3D rawForce = newForces.get(i);
229 | double mass = molecule.contents.get(i).mass; // in amu
230 | Vector3D acceleration = rawForce.scalarMultiply(conversionFactor/mass);
231 | newAccelerations.add(acceleration);
232 | }
233 | }
234 |
235 | // create new point
236 | // kinetic and total energy set by Propagator
237 | return new TrajectoryPoint(time, 0.0, m.potentialEnergy, 0.0,
238 | positions, velocities, newAccelerations, newForces, newForces2,
239 | m.shieldings, result.elapsedTime);
240 | }
241 |
242 | /**
243 | * Writes a block for a MOLDEN movie.
244 | * @param molecule we need the atom symbols
245 | * @return the traj string
246 | */
247 | public String toTrajString(Molecule molecule) {
248 | String trajString = positions.size() + "\n" + potentialEnergy + " Jprogdyn t = " + String.format("%.1f\n", time);
249 | for (int i=0; i < positions.size(); i++) {
250 | String symbol = molecule.contents.get(i).symbol;
251 | Vector3D position = positions.get(i);
252 | trajString = trajString + String.format( "%s %.7f %.7f %.7f\n", symbol, position.getX(), position.getY(), position.getZ() );
253 | }
254 | return trajString;
255 | }
256 |
257 | @Override
258 | public String toString() {
259 | return String.format("Trajectory Point: %.1f fs, PE = %.8f, KE = %.8f, TE = %.8f\n", time, potentialEnergy, kineticEnergy, totalEnergy);
260 | }
261 |
262 | @Override
263 | public int hashCode() {
264 | return Objects.hash(time, kineticEnergy, potentialEnergy, totalEnergy, positions, velocities, accelerations, forces, forces2, shieldings, evaluationTime);
265 | }
266 |
267 | @Override
268 | public boolean equals(Object obj) {
269 | if ( obj == null )
270 | return false;
271 | if ( obj == this )
272 | return true;
273 | if ( !(obj instanceof TrajectoryPoint) )
274 | return false;
275 |
276 | TrajectoryPoint p = (TrajectoryPoint)obj;
277 | if ( time == p.time &&
278 | kineticEnergy == p.kineticEnergy &&
279 | potentialEnergy == p.potentialEnergy &&
280 | totalEnergy == p.totalEnergy &&
281 | positions.equals(p.positions) &&
282 | Objects.equals(velocities, p.velocities) &&
283 | Objects.equals(accelerations, p.accelerations) &&
284 | Objects.equals(forces, p.forces) &&
285 | Objects.equals(forces2, p.forces2) &&
286 | Objects.equals(shieldings, p.shieldings) &&
287 | evaluationTime == p.evaluationTime )
288 | return true;
289 | return false;
290 | }
291 | }
292 |
--------------------------------------------------------------------------------
/src/main/java/edu/harvard/chemistry/ekwan/Jprogdyn/Units.java:
--------------------------------------------------------------------------------
1 | package edu.harvard.chemistry.ekwan.Jprogdyn;
2 |
3 | /**
4 | * This interface holds some unit conversions.
5 | */
6 | public interface Units {
7 |
8 | /** speed of light, cm/s */
9 | public static final double C = 29979245800.0;
10 |
11 | /** Planck's constant, m^2 * kg / s */
12 | public static final double H = 6.626075E-34;
13 |
14 | /** molar gas constant, J / (mol * K) */
15 | public static final double R_GAS_J = 8.31447;
16 |
17 | /** molar gas constant, kcal / (mol * K) */
18 | public static final double R_GAS_KCAL = 0.0019858;
19 |
20 | /** Boltzmann's constant, eV / K */
21 | public static final double BOLTZMANN_EV = 8.61733238E-5;
22 |
23 | /** Boltzmann's constant, kcal / K */
24 | public static final double BOLTZMANN_KCAL = 3.29983E-27;
25 |
26 | /** converts J to kcal/mol */
27 | public static final double J_TO_KCAL_PER_MOL = 6.0221415E23/4184.0;
28 |
29 | /** converts kcal/mol to J */
30 | public static final double KCAL_PER_MOL_TO_J = 4184.0/6.0221415E23;
31 |
32 | /** Avogadro's number */
33 | public static final double AVOGADROS_NUMBER = 6.0221415E23;
34 |
35 | /** Angstroms in a bohr */
36 | public static final double BOHR = 0.52917721092;
37 |
38 | /** kcal per mol/hartree */
39 | public static final double KCAL_PER_HARTREE = 627.509369;
40 |
41 | /** J per mol/hartree */
42 | public static final double J_PER_HARTREE = 2625499.62;
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/edu/harvard/chemistry/ekwan/Jprogdyn/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * This is the javadoc for Jprogdyn. For general information on
3 | * Jprogdyn, please see the README file.
4 | */
5 |
6 | package edu.harvard.chemistry.ekwan.Jprogdyn;
7 |
--------------------------------------------------------------------------------
/src/test/java/edu/harvard/chemistry/ekwan/Jprogdyn/HarmonicTestGaussian.java:
--------------------------------------------------------------------------------
1 | package edu.harvard.chemistry.ekwan.Jprogdyn;
2 |
3 | import java.util.*;
4 | import java.lang.Math;
5 | import org.apache.commons.math3.geometry.euclidean.threed.*;
6 | import java.nio.file.*;
7 |
8 | import junit.framework.Test;
9 | import junit.framework.TestCase;
10 | import junit.framework.TestSuite;
11 |
12 | /**
13 | * This test takes a single normal mode from a molecule, creates positive and negative
14 | * displacements at regular intervals along that mode (up to the classical turning point
15 | * defined by the zero-point energy), and writes the results to a single Gaussian input file
16 | * as a set of --Link1-- commands.
17 | *
18 | * For imaginary frequencies, there is no classical turning point, so displacements are made
19 | * directly in angstroms.
20 | *
21 | * To run: mvn -Dtest=HarmonicTestGaussian test
22 | */
23 | public class HarmonicTestGaussian extends TestCase
24 | {
25 | /**
26 | * Create the test case
27 | *
28 | * @param testName name of the test case
29 | */
30 | public HarmonicTestGaussian( String testName )
31 | {
32 | super( testName );
33 | }
34 |
35 | /**
36 | * Read the molecule, create displacements, then write the results to one Gaussian input file.
37 | */
38 | public void testHarmonicGaussian()
39 | {
40 | // displacement parameters
41 | int modeIndex = 0; // zero-indexed
42 |
43 | double relativeShiftMin = -1.0; // most negative fraction of classical turning point to displace by
44 | double relativeShiftMax = 1.0; // most positive fraction of classical turning point to displace by
45 | double relativeShiftInterval = 0.1; // the displacement step interval in fractions of the classical turning point
46 |
47 | double absoluteShiftMin = -0.005; // used for negative frequencies
48 | double absoluteShiftMax = 0.005; // displacement in angstroms
49 | double absoluteShiftInterval = 0.0005;
50 |
51 | // check parameters
52 | if ( relativeShiftMin >= relativeShiftMax )
53 | throw new IllegalArgumentException("check relative shift min/max");
54 | if ( relativeShiftInterval < 0.0 )
55 | throw new IllegalArgumentException("check relative shift interval");
56 | if ( absoluteShiftMin >= absoluteShiftMax )
57 | throw new IllegalArgumentException("check absolute shift min/max");
58 | if ( absoluteShiftInterval < 0.0 )
59 | throw new IllegalArgumentException("check absolute shift interval");
60 |
61 | // Gaussian parameters
62 | String outputDirectory = "analysis";
63 | int processors = 36;
64 | int memory = 24; // in GB
65 | String footer = "\n";
66 |
67 | // loop through all matching filenames
68 | String path = "test_files";
69 | String glob = "simple*ts*m062x*631+gd*.out";
70 | try ( DirectoryStream dirStream = Files.newDirectoryStream( Paths.get(path), glob)) {
71 | for (Path p : dirStream) {
72 | // read molecule
73 | String moleculeFilename = p.toString();
74 | System.out.printf("\n\nReading data from %s...", moleculeFilename);
75 | GaussianOutputFile frequenciesOutputFile = new GaussianOutputFile(moleculeFilename);
76 | Molecule frequenciesMolecule = frequenciesOutputFile.molecule;
77 | System.out.println("done.");
78 | String routeCard = frequenciesOutputFile.routeCard;
79 | System.out.printf("Original Route: %s\n", routeCard);
80 | routeCard = routeCard.replaceFirst("opt\\S*\\s+?","").replaceFirst("freq\\S*\\s+?","").replaceFirst("#p","#t");
81 | routeCard = routeCard.replaceFirst("opt\\S*$","").replaceFirst("freq\\S*$","");
82 | System.out.printf("Modified Route: %s\n", routeCard);
83 |
84 | // read normal modes
85 | NormalMode mode = frequenciesMolecule.modes.get(modeIndex);
86 | List normalModeCoordinates = mode.coordinates;
87 |
88 | // get normal mode information
89 | double reducedMass = mode.reducedMass; // amu
90 | double forceConstant = mode.forceConstant; // mDyne/A
91 | double frequency = mode.frequency; // cm^-1
92 | double ZPE = -1.0;
93 | double maxShift = -1.0;
94 | System.out.printf("Will use mode %d, which has a frequency of %.1f cm-1.\n", modeIndex+1, mode.frequency);
95 |
96 | // determine shift bounds
97 | double thisShift = 0.0;
98 | double thisMaxShift = 0.0;
99 | double thisShiftStep = 0.0;
100 | double ZPEMaxShift = 0.0;
101 | if ( frequency < 0.0 ) {
102 | thisShift = absoluteShiftMin;
103 | thisMaxShift = absoluteShiftMax;
104 | thisShiftStep = absoluteShiftInterval;
105 | }
106 | else {
107 | thisShift = relativeShiftMin;
108 | thisMaxShift = relativeShiftMax;
109 | thisShiftStep = relativeShiftInterval;
110 | ZPEMaxShift = HarmonicOscillatorDistribution.getClassicalTurningPoint(ZPE, forceConstant); // in Angstroms
111 | }
112 |
113 | // generate output file header
114 | StringBuilder outputStringBuilder = new StringBuilder();
115 | int numberOfGeometries = 0;
116 | for (; thisShift <= thisMaxShift+0.00001; thisShift += thisShiftStep) {
117 | // calculate displacements
118 | numberOfGeometries++;
119 | List finalPositions = new ArrayList<>(frequenciesMolecule.contents.size());
120 | for (int i=0; i < normalModeCoordinates.size(); i++) {
121 | Vector3D direction = normalModeCoordinates.get(i);
122 | Vector3D currentPosition = frequenciesMolecule.contents.get(i).position;
123 | double scalar = frequency < 0.0 ? thisShift : thisShift * ZPEMaxShift;
124 | Vector3D displacement = direction.scalarMultiply(scalar);
125 | Vector3D finalPosition = currentPosition.add(displacement);
126 | finalPositions.add(finalPosition);
127 | }
128 |
129 | boolean firstGeometry = outputStringBuilder.length() == 0;
130 | if ( ! firstGeometry )
131 | outputStringBuilder.append("--Link1--\n");
132 | outputStringBuilder.append("%chk=checkpoint.chk\n");
133 | outputStringBuilder.append(String.format("%%mem=%dGB\n", memory));
134 | outputStringBuilder.append(String.format("%%nprocshared=%d\n", processors));
135 | if ( firstGeometry )
136 | outputStringBuilder.append(routeCard + "\n");
137 | else
138 | outputStringBuilder.append(routeCard + " guess=read\n");
139 | if ( frequency < 0.0 )
140 | outputStringBuilder.append(String.format("\ndisplacement: %.6f A\n\n", thisShift));
141 | else
142 | outputStringBuilder.append(String.format("\ndisplacement: %.6f A\n\n", thisShift * ZPEMaxShift));
143 | outputStringBuilder.append(String.format("%d %d\n", frequenciesMolecule.charge, frequenciesMolecule.multiplicity));
144 | for (int i=0; i < frequenciesMolecule.contents.size(); i++) {
145 | String symbol = frequenciesMolecule.contents.get(i).symbol;
146 | double x = finalPositions.get(i).getX();
147 | double y = finalPositions.get(i).getY();
148 | double z = finalPositions.get(i).getZ();
149 | outputStringBuilder.append(String.format(" %-5s %15.10f %15.10f %15.10f\n", symbol, x, y, z));
150 | }
151 | if ( footer.trim().length() > 0 )
152 | outputStringBuilder.append(footer + "\n");
153 | outputStringBuilder.append("\n\n");
154 | }
155 |
156 | // write out file
157 | String outputFilename = p.getFileName().toString().replaceFirst(".out",".gjf").replaceFirst("-ts-","-displacements-");
158 | String outputFullFilename = String.format("%s/%s", outputDirectory, outputFilename);
159 | InputFileFormat.writeStringToDisk(outputStringBuilder.toString(),outputFullFilename);
160 | System.out.printf(">>> Wrote %d geometries to %s.\n", numberOfGeometries, outputFullFilename);
161 | }
162 | }
163 | catch (Exception e) { e.printStackTrace(); }
164 | assertTrue( true );
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/src/test/java/edu/harvard/chemistry/ekwan/Jprogdyn/InitializerTest.java:
--------------------------------------------------------------------------------
1 | package edu.harvard.chemistry.ekwan.Jprogdyn;
2 |
3 | import java.util.*;
4 | import java.lang.Math;
5 | import org.apache.commons.math3.geometry.euclidean.threed.*;
6 | import com.google.common.collect.*;
7 |
8 | import junit.framework.Test;
9 | import junit.framework.TestCase;
10 | import junit.framework.TestSuite;
11 |
12 | /**
13 | * This test generates thermal initializations from a file and writes the
14 | * geometries to a set of files. These files are intended as input for
15 | * other programs like Gaussian.
16 | *
17 | * The first structure will be unperturbed.
18 | *
19 | * To run: mvn -Dtest=InitializerTest test
20 | */
21 | public class InitializerTest extends TestCase
22 | {
23 | /**
24 | * Create the test case
25 | *
26 | * @param testName name of the test case
27 | */
28 | public InitializerTest( String testName )
29 | {
30 | super( testName );
31 | }
32 |
33 | /**
34 | *
35 | */
36 | public void testInitializer()
37 | {
38 | // displacement parameters
39 | String moleculeFilename = "test_files/methane_b3lyp_midix.out"; // filename to read modes from
40 | double temperature = 298.0; // in K
41 | int numberOfInitializations = 1; // how many files to make
42 | Map specialModeInitializationMap = new HashMap<>(); // zero-indexed mode number --> initialization type
43 | //specialModeInitializationMap.put(0,Initializer.VibrationalInitializationType.NONE); // don't displace the TS mode
44 |
45 | // Gaussian parameters
46 | String outputPrefix = moleculeFilename.replace("test_files","analysis").replace(".out","");
47 | String footer = "\n";
48 |
49 | // read molecule
50 | System.out.println("Loading data...\n");
51 | GaussianOutputFile frequenciesOutputFile = new GaussianOutputFile(moleculeFilename);
52 | Molecule molecule = frequenciesOutputFile.molecule;
53 | System.out.printf("Molecule read from %s:\n", moleculeFilename);
54 | System.out.println(molecule);
55 | System.out.println();
56 | System.out.println("Normal modes:");
57 | for (int i=0; i < molecule.modes.size(); i++) {
58 | NormalMode mode = molecule.modes.get(i);
59 | System.out.printf("Mode %4d : %.0f cm-1\n", i, mode.frequency);
60 | }
61 |
62 | // make dummy dynamics method
63 | CalculationMethod dynamicsMethod = new GaussianCalculationMethod(CalculationMethod.CalculationType.ENERGY_AND_FORCE,
64 | 3, 4, "#p", footer);
65 |
66 | // make Initializer object
67 | Initializer initializer = new Initializer(molecule, // the molecule with frequencies to initialize with
68 | temperature, // in K
69 | 1.0, // timestep in fs (irrelevant here)
70 | Initializer.VibrationalInitializationType.QUASICLASSICAL, // default vibrational initialization type
71 | Initializer.RotationalInitializationType.NONE, // no need for rotations here
72 | specialModeInitializationMap, // treat some modes differently as specified here
73 | 0.1, // harmonic tolerance in percent (irrelevant)
74 | dynamicsMethod, // dynamics method (irrelevant)
75 | 1.0); // frequency scaling factor (irrelevant)
76 |
77 | // generate input files
78 | // first structure will be unperturbed
79 | for (int i=0; i < numberOfInitializations; i++) {
80 | System.out.printf("\n>>> Iteration %3d of %3d <<<\n", i+1, numberOfInitializations);
81 |
82 | // generate a new initialization
83 | Molecule newMolecule = molecule;
84 | //if ( i>0 )
85 | newMolecule = initializer.generateStructure(molecule);
86 | //else
87 | // System.out.println("[ Not perturbing molecule for first iteration. ]");
88 |
89 | // write out molecule
90 | StringBuilder s = new StringBuilder();
91 | s.append(String.format("%d %d\n", molecule.charge, molecule.multiplicity));
92 | for (int j=0; j < molecule.contents.size(); j++) {
93 | String symbol = newMolecule.contents.get(j).symbol;
94 | double x = newMolecule.contents.get(j).position.getX();
95 | double y = newMolecule.contents.get(j).position.getY();
96 | double z = newMolecule.contents.get(j).position.getZ();
97 | s.append(String.format(" %-5s %15.10f %15.10f %15.10f\n", symbol, x, y, z));
98 | }
99 | String filename = String.format("%s-init_%03d.gjf", outputPrefix, i);
100 | InputFileFormat.writeStringToDisk(s.toString(),filename);
101 | System.out.printf("> Wrote to %s.\n\n", filename);
102 | }
103 |
104 | assertTrue( true );
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/tutorials/methane_NMR_analysis.config:
--------------------------------------------------------------------------------
1 | ### Jprogdyn Configuration File ###
2 |
3 | # This file controls the behavior of Jprogdyn.
4 | # By default, Jprogdyn will use "Jprogdyn.conf" as the current configuration file.
5 | #
6 | # To switch to a custom file:
7 | # mvn exec:java -Dconfig.filename="another.config"
8 |
9 | # Blank lines and comments starting with # are ignored.
10 | # Comments may be placed after any configuration value with a #.
11 | # All options must be specified on one line.
12 |
13 |
14 | # File/Directory Locations
15 | working_directory : use_current # specify full path or "use_current" to use the current working directory
16 |
17 | frequency_directory : test_files # path relative to working_directory where Jprogdyn should expect the
18 | # Gaussian output files to use for initializing trajectories
19 |
20 | frequency_file : methane_b3lyp_midix.out # the file to read in frequencies from (Gaussian output with freq=hpmodes)
21 |
22 | gaussian_directory : gaussian # path relative to working_directory in which to run Gaussian jobs
23 | # run_gaussian.sh is expected in this directory
24 |
25 | gaussian_max_filenames : 10000 # maximum number of job filenames (should not need to be changed)
26 |
27 |
28 | # Threading Options
29 | number_of_simultaneous_trajectories : 9 # how many trajectories to run simultaneously
30 |
31 |
32 | # Gaussian Options
33 | number_of_processors_per_trajectory : 4 # how many processors to use per Gaussian job
34 |
35 | memory_per_trajectory : 3 # how much RAM to use per trajectory in GB
36 |
37 | gaussian_force_route_card : b3lyp/midix pop=none # the route card to pass to Gaussian for a regular force job
38 | # Jprogdyn will add all other necessary keywords -- just put in
39 | # the level of theory/solvation
40 |
41 | gaussian_force_footer : @blank # stuff to put at the end of every force job (one line please)
42 |
43 |
44 | # Trajectory Options
45 | job_type : analysis # specify "trajectory" to run trajectories or "analysis"
46 | # to analyze existing checkpoints
47 |
48 | trajectory_type : nmr # specify "reaction" to run/analyze a reaction trajectory or
49 | # specify "nmr" to run/analyze an NMR trajectory
50 |
51 | number_of_total_trajectories : 25 # how many trajectories to run in total
52 |
53 | checkpoint_directory : checkpoints # path relative to working_directory where Jprogdyn should expect the
54 | # any existing trajectory checpoints to be (progress will also be
55 | # saved here)
56 |
57 | checkpoint_prefix : methane # all checkpoint files will have this prefix
58 |
59 | checkpoint_interval : 5 # save progress every n points, must be between 1 and 50 inclusive
60 |
61 | temperature : 298.0 # in K
62 |
63 | timestep : 1.0 # timestep in fs
64 |
65 | number_of_forward_points : 125 # how many forward points to compute
66 |
67 | number_of_backward_points : 125 # how many backward points to compute
68 |
69 | # Initialization Options
70 | maximum_number_of_initialization_attempts : 50 # try to initialize this many times per trajectory then give up
71 | # must be at least 10
72 |
73 | harmonic_tolerance : 0.01 # the maximum allowable difference between the desired and actual
74 | # energies of the initial structure in percent
75 | # must be at least 0.00001 and less than 10.0
76 | # 0.01 is a good starting value
77 |
78 | scale_factor : 1.0 # vibrational frequencies will be scaled by this factor
79 | # (1.0 recommended, which is to say no scaling)
80 | # must be between 0.5 and 1.5
81 |
82 | # draw the initial displacements from...
83 | # quasiclassical = a quantum mechanical canonical ensemble
84 | # classical = a classical mechanical canonical ensemble
85 | # uniform = a uniform classical distribution
86 | # ts_positive = zero displacement but forward velocity
87 | # ts_negative = zero displacement but negative velocity
88 | # ts_random = zero displacement but random velocity sign
89 | # none = do not displace
90 |
91 | vibrational_initialization_default : quasiclassical # all vibrational modes will be initialized this way unless specified
92 | # otherwise below
93 |
94 | vibrational_initialization_override : no_overrides # set to no_overrides or a semicolon-separated list of the form
95 | # 0:ts_positive;1:none
96 | # which means initialize mode 0 with no displacements and positive
97 | # velocity and initialize mode 1 with no displacements and no velocity
98 | # modes are 0-indexed
99 |
100 | rotational_initialization_type : classical # what kind of rotational initialization to do (classical or none)
101 |
102 |
103 | # Reaction Trajectory Termination Conditions
104 | # Note: these options will be ignored if trajectory_type is set to "nmr."
105 | #
106 | # If you want to run all points, comment out all these lines.
107 | # If you want to specify more than one termination condition, add multiple lines that start with
108 | # "termination_condition". If any condition is met, the trajectory will stop.
109 | #
110 | # To use no termination conditions, write a single line:
111 | # termination_condition : no_termination_conditions
112 | #
113 | # In this example, the first condition means to stop the trajectory if the C-F bond distance
114 | # between atoms 8 and 13 exceeds 3 A. Atom numbers are 1-indexed.
115 | #
116 | # termination_condition : bond_length, 8, 13, C-F, greater_than, 3.0
117 | #
118 | # These termination conditions will also be used to assign trajectory outcomes if
119 | # summarize_trajectories_to_screen is set to "yes".
120 |
121 | # description of fields:
122 | termination_condition : no_termination_conditions # bond_length, bond_angle, torsion
123 | # next fields = atom numbers (2, 3, or 4 fields)
124 | # description = one word
125 | # last two fields:
126 | # stop when the internal coordinate is greater_than, equal, or
127 | # less_than to the given number
128 |
129 | # NMR Calculations
130 | # Note: these options will be ignored if trajectory_type is set to "reaction".
131 |
132 | nmr_point_interval : 8 # how often in number of trajectory points to calculate NMR shieldings
133 | # (8 is recommended)
134 |
135 | shieldings_file : methane_b3lyp_midix_NMR_b3lyp_dz.out # the file containing the NMR shieldings for the stationary point
136 | # at the NMR level of theory
137 | # (expected in working_directory/frequency_directory)
138 |
139 | gaussian_nmr_route_card : b3lyp/cc-pvdz # the route card to pass to Gaussian for an NMR job
140 | # place in quotes, all one line, use \n for new lines
141 | # Jprogdyn will add all other necessary keywords -- just put in
142 | # the level of theory/solvation, don't add NMR keyword
143 |
144 | gaussian_nmr_footer : @blank # stuff to put at the end of every NMR job (one line please)
145 |
146 | symmetry_groups : @blank # list of sets of symmetry-related atoms to average shieldings over
147 | # use a semicolon to specify multiple groups
148 |
149 |
150 | # Analysis Options
151 | # Note: these options will only be processed if job_type is set to "analysis."
152 | analysis_directory : analysis # path relative to working_directory where Jprogdyn will save
153 | # MOLDEN movies to
154 |
155 | make_molden_movies : yes # if "yes" will make movies of each trajectory and save it to
156 | # analysis_directory (any existing movies will be overwritten)
157 | # files will be named checkpoint_filename.traj
158 |
159 | summarize_trajectories_to_screen : yes # if "yes" parse the list of analysis_coordinates below,
160 | # analyze each trajectory, and print the report to the screen
161 |
162 | summary_interval : 20 # when printing out a report of the trajectories to the screen,
163 | # how often to print out updates, given in trajectory points
164 | # recommended: 20
165 |
166 | # place multiple analysis_coordinate entries on separate lines
167 | # to use no analysis coordinates, write a single line:
168 | # analysis_coordinate : no_analysis_coordinates
169 | # description of fields:
170 | analysis_coordinate : bond_length, 1, 2, C-H2 # bond_length, bond_angle, torsion
171 | analysis_coordinate : bond_angle, 2, 1, 3, H2-C-H3 # next fields = atom numbers (2, 3, or 4 fields)
172 | # description = one word
173 |
174 | write_analysis_csv : yes # if "yes", write a comma-separated file containing the
175 | # above coordinates as a function of time for each trajectory
176 | # to a analysis_directory/checkpoint_filename.dat
177 | # (this means one csv file per trajectory)
178 |
--------------------------------------------------------------------------------
/tutorials/methane_NMR_trajectories.config:
--------------------------------------------------------------------------------
1 | ### Jprogdyn Configuration File ###
2 |
3 | # This file controls the behavior of Jprogdyn.
4 | # By default, Jprogdyn will use "Jprogdyn.conf" as the current configuration file.
5 | #
6 | # To switch to a custom file:
7 | # mvn exec:java -Dconfig.filename="another.config"
8 |
9 | # Blank lines and comments starting with # are ignored.
10 | # Comments may be placed after any configuration value with a #.
11 | # All options must be specified on one line.
12 |
13 |
14 | # File/Directory Locations
15 | working_directory : use_current # specify full path or "use_current" to use the current working directory
16 |
17 | frequency_directory : test_files # path relative to working_directory where Jprogdyn should expect the
18 | # Gaussian output files to use for initializing trajectories
19 |
20 | frequency_file : methane_b3lyp_midix.out # the file to read in frequencies from (Gaussian output with freq=hpmodes)
21 |
22 | gaussian_directory : gaussian # path relative to working_directory in which to run Gaussian jobs
23 | # run_gaussian.sh is expected in this directory
24 |
25 | gaussian_max_filenames : 10000 # maximum number of job filenames (should not need to be changed)
26 |
27 |
28 | # Threading Options
29 | number_of_simultaneous_trajectories : 9 # how many trajectories to run simultaneously
30 |
31 |
32 | # Gaussian Options
33 | number_of_processors_per_trajectory : 4 # how many processors to use per Gaussian job
34 |
35 | memory_per_trajectory : 3 # how much RAM to use per trajectory in GB
36 |
37 | gaussian_force_route_card : b3lyp/midix pop=none # the route card to pass to Gaussian for a regular force job
38 | # Jprogdyn will add all other necessary keywords -- just put in
39 | # the level of theory/solvation
40 |
41 | gaussian_force_footer : @blank # stuff to put at the end of every force job (one line please)
42 |
43 |
44 | # Trajectory Options
45 | job_type : trajectory # specify "trajectory" to run trajectories or "analysis"
46 | # to analyze existing checkpoints
47 |
48 | trajectory_type : nmr # specify "reaction" to run/analyze a reaction trajectory or
49 | # specify "nmr" to run/analyze an NMR trajectory
50 |
51 | number_of_total_trajectories : 25 # how many trajectories to run in total
52 |
53 | checkpoint_directory : checkpoints # path relative to working_directory where Jprogdyn should expect the
54 | # any existing trajectory checpoints to be (progress will also be
55 | # saved here)
56 |
57 | checkpoint_prefix : methane # all checkpoint files will have this prefix
58 |
59 | checkpoint_interval : 5 # save progress every n points, must be between 1 and 50 inclusive
60 |
61 | temperature : 298.0 # in K
62 |
63 | timestep : 1.0 # timestep in fs
64 |
65 | number_of_forward_points : 125 # how many forward points to compute
66 |
67 | number_of_backward_points : 125 # how many backward points to compute
68 |
69 | # Initialization Options
70 | maximum_number_of_initialization_attempts : 50 # try to initialize this many times per trajectory then give up
71 | # must be at least 10
72 |
73 | harmonic_tolerance : 0.01 # the maximum allowable difference between the desired and actual
74 | # energies of the initial structure in percent
75 | # must be at least 0.00001 and less than 10.0
76 | # 0.01 is a good starting value
77 |
78 | scale_factor : 1.0 # vibrational frequencies will be scaled by this factor
79 | # (1.0 recommended, which is to say no scaling)
80 | # must be between 0.5 and 1.5
81 |
82 | # draw the initial displacements from...
83 | # quasiclassical = a quantum mechanical canonical ensemble
84 | # classical = a classical mechanical canonical ensemble
85 | # uniform = a uniform classical distribution
86 | # ts_positive = zero displacement but forward velocity
87 | # ts_negative = zero displacement but negative velocity
88 | # ts_random = zero displacement but random velocity sign
89 | # none = do not displace
90 |
91 | vibrational_initialization_default : quasiclassical # all vibrational modes will be initialized this way unless specified
92 | # otherwise below
93 |
94 | vibrational_initialization_override : no_overrides # set to no_overrides or a semicolon-separated list of the form
95 | # 0:ts_positive;1:none
96 | # which means initialize mode 0 with no displacements and positive
97 | # velocity and initialize mode 1 with no displacements and no velocity
98 | # modes are 0-indexed
99 |
100 | rotational_initialization_type : classical # what kind of rotational initialization to do (classical or none)
101 |
102 |
103 | # Reaction Trajectory Termination Conditions
104 | # Note: these options will be ignored if trajectory_type is set to "nmr."
105 | #
106 | # If you want to run all points, comment out all these lines.
107 | # If you want to specify more than one termination condition, add multiple lines that start with
108 | # "termination_condition". If any condition is met, the trajectory will stop.
109 | #
110 | # To use no termination conditions, write a single line:
111 | # termination_condition : no_termination_conditions
112 | #
113 | # In this example, the first condition means to stop the trajectory if the C-F bond distance
114 | # between atoms 8 and 13 exceeds 3 A. Atom numbers are 1-indexed.
115 | #
116 | # termination_condition : bond_length, 8, 13, C-F, greater_than, 3.0
117 | #
118 | # These termination conditions will also be used to assign trajectory outcomes if
119 | # summarize_trajectories_to_screen is set to "yes".
120 |
121 | # description of fields:
122 | termination_condition : no_termination_conditions # bond_length, bond_angle, torsion
123 | # next fields = atom numbers (2, 3, or 4 fields)
124 | # description = one word
125 | # last two fields:
126 | # stop when the internal coordinate is greater_than, equal, or
127 | # less_than to the given number
128 |
129 |
130 | # NMR Calculations
131 | # Note: these options will be ignored if trajectory_type is set to "reaction".
132 |
133 | nmr_point_interval : 8 # how often in number of trajectory points to calculate NMR shieldings
134 | # (8 is recommended)
135 |
136 | shieldings_file : methane_b3lyp_midix_NMR_b3lyp_dz.out # the file containing the NMR shieldings for the stationary point
137 | # at the NMR level of theory
138 | # (expected in working_directory/frequency_directory)
139 |
140 | gaussian_nmr_route_card : b3lyp/cc-pvdz # the route card to pass to Gaussian for an NMR job
141 | # place in quotes, all one line, use \n for new lines
142 | # Jprogdyn will add all other necessary keywords -- just put in
143 | # the level of theory/solvation, don't add NMR keyword
144 |
145 | gaussian_nmr_footer : @blank # stuff to put at the end of every NMR job (one line please)
146 |
147 | symmetry_groups : @blank # list of sets of symmetry-related atoms to average shieldings over
148 | # use a semicolon to specify multiple groups
149 |
150 |
151 | # Analysis Options
152 | # Note: these options will only be processed if job_type is set to "analysis."
153 | analysis_directory : analysis # path relative to working_directory where Jprogdyn will save
154 | # MOLDEN movies to
155 |
156 | make_molden_movies : yes # if "yes" will make movies of each trajectory and save it to
157 | # analysis_directory (any existing movies will be overwritten)
158 | # files will be named checkpoint_filename.traj
159 |
160 | summarize_trajectories_to_screen : yes # if "yes" parse the list of analysis_coordinates below,
161 | # analyze each trajectory, and print the report to the screen
162 |
163 | summary_interval : 20 # when printing out a report of the trajectories to the screen,
164 | # how often to print out updates, given in trajectory points
165 | # recommended: 20
166 |
167 | # place multiple analysis_coordinate entries on separate lines
168 | # to use no analysis coordinates, write a single line:
169 | # analysis_coordinate : no_analysis_coordinates
170 | # description of fields:
171 | analysis_coordinate : bond_length, 1, 2, C-H2 # bond_length, bond_angle, torsion
172 | analysis_coordinate : bond_angle, 2, 1, 3, H2-C-H3 # next fields = atom numbers (2, 3, or 4 fields)
173 | # description = one word
174 |
175 | write_analysis_csv : yes # if "yes", write a comma-separated file containing the
176 | # above coordinates as a function of time for each trajectory
177 | # to a analysis_directory/checkpoint_filename.dat
178 | # (this means one csv file per trajectory)
179 |
--------------------------------------------------------------------------------
/tutorials/reaction_tutorial_analysis.config:
--------------------------------------------------------------------------------
1 | ### Jprogdyn Configuration File ###
2 |
3 | # This file controls the behavior of Jprogdyn.
4 | # By default, Jprogdyn will use "Jprogdyn.conf" as the current configuration file.
5 | #
6 | # To switch to a custom file:
7 | # mvn exec:java -Dconfig.filename="another.config"
8 |
9 | # Blank lines and comments starting with # are ignored.
10 | # Comments may be placed after any configuration value with a #.
11 | # All options must be specified on one line.
12 |
13 |
14 | # File/Directory Locations
15 | working_directory : use_current # specify full path or "use_current" to use the current working directory
16 |
17 | frequency_directory : test_files # path relative to working_directory where Jprogdyn should expect the
18 | # Gaussian output files to use for initializing trajectories
19 |
20 | frequency_file : dinitro_Cl_F-1H2O-ts-b3lyp_d3bj-631+gd-dmf_pcm.out # the file to read in frequencies from (Gaussian output with freq=hpmodes)
21 |
22 | gaussian_directory : gaussian # path relative to working_directory in which to run Gaussian jobs
23 | # run_gaussian.sh is expected in this directory
24 |
25 | gaussian_max_filenames : 10000 # maximum number of job filenames (should not need to be changed)
26 |
27 |
28 | # Threading Options
29 | number_of_simultaneous_trajectories : 4 # how many trajectories to run simultaneously
30 |
31 |
32 | # Gaussian Options
33 | number_of_processors_per_trajectory : 9 # how many processors to use per Gaussian job
34 |
35 | memory_per_trajectory : 24 # how much RAM to use per trajectory in GB
36 |
37 | # the route card to pass to Gaussian for a regular force job
38 | gaussian_force_route_card : b3lyp scrf=(solvent=n,n-dimethylformamide,pcm) empiricaldispersion=gd3bj 6-31+g* pop=none
39 | # Jprogdyn will add all other necessary keywords -- just put in
40 | # the level of theory/solvation
41 |
42 | gaussian_force_footer : @blank # stuff to put at the end of every force job (one line please)
43 |
44 |
45 | # Trajectory Options
46 | job_type : analysis # specify "trajectory" to run trajectories or "analysis"
47 | # to analyze existing checkpoints
48 |
49 | trajectory_type : reaction # specify "reaction" to run/analyze a reaction trajectory or
50 | # specify "nmr" to run/analyze an NMR trajectory
51 |
52 | number_of_total_trajectories : 4 # how many trajectories to run in total
53 |
54 | checkpoint_directory : checkpoints # path relative to working_directory where Jprogdyn should expect the
55 | # any existing trajectory checpoints to be (progress will also be
56 | # saved here)
57 |
58 | checkpoint_prefix : SNAr_tutorial # all checkpoint files will have this prefix
59 |
60 | checkpoint_interval : 5 # save progress every n points, must be between 1 and 50 inclusive
61 |
62 | temperature : 298.0 # in K
63 |
64 | timestep : 1.0 # timestep in fs
65 |
66 | number_of_forward_points : 500 # how many forward points to compute
67 |
68 | number_of_backward_points : 500 # how many backward points to compute
69 |
70 | # Initialization Options
71 | maximum_number_of_initialization_attempts : 50 # try to initialize this many times per trajectory then give up
72 | # must be at least 10
73 |
74 | harmonic_tolerance : 0.0005 # the maximum allowable difference between the desired and actual
75 | # energies of the initial structure in percent
76 | # must be at least 0.00001 and less than 10.0
77 | # 0.01 is a good starting value
78 |
79 | scale_factor : 1.0 # vibrational frequencies will be scaled by this factor
80 | # (1.0 recommended, which is to say no scaling)
81 | # must be between 0.5 and 1.5
82 |
83 | # draw the initial displacements from...
84 | # quasiclassical = a quantum mechanical canonical ensemble
85 | # classical = a classical mechanical canonical ensemble
86 | # uniform = a uniform classical distribution
87 | # ts_positive = zero displacement but forward velocity
88 | # ts_negative = zero displacement but negative velocity
89 | # ts_random = zero displacement but random velocity sign
90 | # none = do not displace
91 |
92 | vibrational_initialization_default : quasiclassical # all vibrational modes will be initialized this way unless specified
93 | # otherwise below
94 |
95 | vibrational_initialization_override : 0:ts_positive # set to no_overrides or a semicolon-separated list of the form
96 | # 0:ts_positive;1:none
97 | # which means initialize mode 0 with no displacements and positive
98 | # velocity and initialize mode 1 with no displacements and no velocity
99 | # modes are 0-indexed
100 |
101 | rotational_initialization_type : classical # what kind of rotational initialization to do (classical or none)
102 |
103 |
104 | # Reaction Trajectory Termination Conditions
105 | # Note: these options will be ignored if trajectory_type is set to "nmr."
106 | #
107 | # If you want to run all points, comment out all these lines.
108 | # If you want to specify more than one termination condition, add multiple lines that start with
109 | # "termination_condition". If any condition is met, the trajectory will stop.
110 | #
111 | # To use no termination conditions, write a single line:
112 | # termination_condition : no_termination_conditions
113 | #
114 | # In this example, the first condition means to stop the trajectory if the C-F bond distance
115 | # between atoms 8 and 13 exceeds 3 A. Atom numbers are 1-indexed.
116 | #
117 | # termination_condition : bond_length, 8, 13, C-F, greater_than, 3.0
118 | #
119 | # These termination conditions will also be used to assign trajectory outcomes if
120 | # summarize_trajectories_to_screen is set to "yes".
121 |
122 | termination_condition : bond_length, 8, 13, starting_material, greater_than, 3.0 # description of fields:
123 | termination_condition : bond_length, 8, 17, product, greater_than, 4.0 # bond_length, bond_angle, torsion
124 | # next fields = atom numbers (2, 3, or 4 fields)
125 | # description = one word
126 | # last two fields:
127 | # stop when the internal coordinate is greater_than, equal, or
128 | # less_than to the given number
129 |
130 | # NMR Calculations
131 | # Note: these options will be ignored if trajectory_type is set to "reaction".
132 |
133 | nmr_point_interval : 8 # how often in number of trajectory points to calculate NMR shieldings
134 | # (8 is recommended)
135 |
136 | shieldings_file : @blank # the file containing the NMR shieldings for the stationary point
137 | # at the NMR level of theory
138 | # (expected in working_directory/frequency_directory)
139 |
140 | gaussian_nmr_route_card : b3lyp/cc-pvdz # the route card to pass to Gaussian for an NMR job
141 | # place in quotes, all one line, use \n for new lines
142 | # Jprogdyn will add all other necessary keywords -- just put in
143 | # the level of theory/solvation, don't add NMR keyword
144 |
145 | gaussian_nmr_footer : @blank # stuff to put at the end of every NMR job (one line please)
146 |
147 | symmetry_groups : @blank # list of sets of symmetry-related atoms to average shieldings over
148 | # use a semicolon to specify multiple groups
149 |
150 |
151 | # Analysis Options
152 | # Note: these options will only be processed if job_type is set to "analysis."
153 | analysis_directory : analysis # path relative to working_directory where Jprogdyn will save
154 | # MOLDEN movies to
155 |
156 | make_molden_movies : yes # if "yes" will make movies of each trajectory and save it to
157 | # analysis_directory (any existing movies will be overwritten)
158 | # files will be named checkpoint_filename.traj
159 |
160 | summarize_trajectories_to_screen : yes # if "yes" parse the list of analysis_coordinates below,
161 | # analyze each trajectory, and print the report to the screen
162 |
163 | summary_interval : 100 # when printing out a report of the trajectories to the screen,
164 | # how often to print out updates, given in trajectory points
165 | # recommended: 20
166 |
167 | # place multiple analysis_coordinate entries on separate lines
168 | # to use no analysis coordinates, write a single line:
169 | # analysis_coordinate : no_analysis_coordinates
170 | # description of fields:
171 | analysis_coordinate : bond_length, 8, 13, C-F # bond_length, bond_angle, torsion
172 | analysis_coordinate : bond_length, 8, 17, C-Cl # next fields = atom numbers (2, 3, or 4 fields)
173 | # description = one word
174 |
175 | write_analysis_csv : yes # if "yes", write a comma-separated file containing the
176 | # above coordinates as a function of time for each trajectory
177 | # to a analysis_directory/checkpoint_filename.dat
178 | # (this means one csv file per trajectory)
179 |
--------------------------------------------------------------------------------
/tutorials/reaction_tutorial_trajectories.config:
--------------------------------------------------------------------------------
1 | ### Jprogdyn Configuration File ###
2 |
3 | # This file controls the behavior of Jprogdyn.
4 | # By default, Jprogdyn will use "Jprogdyn.conf" as the current configuration file.
5 | #
6 | # To switch to a custom file:
7 | # mvn exec:java -Dconfig.filename="another.config"
8 |
9 | # Blank lines and comments starting with # are ignored.
10 | # Comments may be placed after any configuration value with a #.
11 | # All options must be specified on one line.
12 |
13 |
14 | # File/Directory Locations
15 | working_directory : use_current # specify full path or "use_current" to use the current working directory
16 |
17 | frequency_directory : test_files # path relative to working_directory where Jprogdyn should expect the
18 | # Gaussian output files to use for initializing trajectories
19 |
20 | frequency_file : dinitro_Cl_F-1H2O-ts-b3lyp_d3bj-631+gd-dmf_pcm.out # the file to read in frequencies from (Gaussian output with freq=hpmodes)
21 |
22 | gaussian_directory : gaussian # path relative to working_directory in which to run Gaussian jobs
23 | # run_gaussian.sh is expected in this directory
24 |
25 | gaussian_max_filenames : 10000 # maximum number of job filenames (should not need to be changed)
26 |
27 |
28 | # Threading Options
29 | number_of_simultaneous_trajectories : 4 # how many trajectories to run simultaneously
30 |
31 |
32 | # Gaussian Options
33 | number_of_processors_per_trajectory : 9 # how many processors to use per Gaussian job
34 |
35 | memory_per_trajectory : 24 # how much RAM to use per trajectory in GB
36 |
37 | # the route card to pass to Gaussian for a regular force job
38 | gaussian_force_route_card : b3lyp scrf=(solvent=n,n-dimethylformamide,pcm) empiricaldispersion=gd3bj 6-31+g* pop=none
39 | # Jprogdyn will add all other necessary keywords -- just put in
40 | # the level of theory/solvation
41 |
42 | gaussian_force_footer : @blank # stuff to put at the end of every force job (one line please)
43 |
44 |
45 | # Trajectory Options
46 | job_type : trajectory # specify "trajectory" to run trajectories or "analysis"
47 | # to analyze existing checkpoints
48 |
49 | trajectory_type : reaction # specify "reaction" to run/analyze a reaction trajectory or
50 | # specify "nmr" to run/analyze an NMR trajectory
51 |
52 | number_of_total_trajectories : 4 # how many trajectories to run in total
53 |
54 | checkpoint_directory : checkpoints # path relative to working_directory where Jprogdyn should expect the
55 | # any existing trajectory checpoints to be (progress will also be
56 | # saved here)
57 |
58 | checkpoint_prefix : SNAr_tutorial # all checkpoint files will have this prefix
59 |
60 | checkpoint_interval : 5 # save progress every n points, must be between 1 and 50 inclusive
61 |
62 | temperature : 298.0 # in K
63 |
64 | timestep : 1.0 # timestep in fs
65 |
66 | number_of_forward_points : 500 # how many forward points to compute
67 |
68 | number_of_backward_points : 500 # how many backward points to compute
69 |
70 | # Initialization Options
71 | maximum_number_of_initialization_attempts : 50 # try to initialize this many times per trajectory then give up
72 | # must be at least 10
73 |
74 | harmonic_tolerance : 0.0005 # the maximum allowable difference between the desired and actual
75 | # energies of the initial structure in percent
76 | # must be at least 0.00001 and less than 10.0
77 | # 0.01 is a good starting value
78 |
79 | scale_factor : 1.0 # vibrational frequencies will be scaled by this factor
80 | # (1.0 recommended, which is to say no scaling)
81 | # must be between 0.5 and 1.5
82 |
83 | # draw the initial displacements from...
84 | # quasiclassical = a quantum mechanical canonical ensemble
85 | # classical = a classical mechanical canonical ensemble
86 | # uniform = a uniform classical distribution
87 | # ts_positive = zero displacement but forward velocity
88 | # ts_negative = zero displacement but negative velocity
89 | # ts_random = zero displacement but random velocity sign
90 | # none = do not displace
91 |
92 | vibrational_initialization_default : quasiclassical # all vibrational modes will be initialized this way unless specified
93 | # otherwise below
94 |
95 | vibrational_initialization_override : 0:ts_positive # set to no_overrides or a semicolon-separated list of the form
96 | # 0:ts_positive;1:none
97 | # which means initialize mode 0 with no displacements and positive
98 | # velocity and initialize mode 1 with no displacements and no velocity
99 | # modes are 0-indexed
100 |
101 | rotational_initialization_type : classical # what kind of rotational initialization to do (classical or none)
102 |
103 |
104 | # Reaction Trajectory Termination Conditions
105 | # Note: these options will be ignored if trajectory_type is set to "nmr."
106 | #
107 | # If you want to run all points, comment out all these lines.
108 | # If you want to specify more than one termination condition, add multiple lines that start with
109 | # "termination_condition". If any condition is met, the trajectory will stop.
110 | #
111 | # To use no termination conditions, write a single line:
112 | # termination_condition : no_termination_conditions
113 | #
114 | # In this example, the first condition means to stop the trajectory if the C-F bond distance
115 | # between atoms 8 and 13 exceeds 3 A. Atom numbers are 1-indexed.
116 | #
117 | # termination_condition : bond_length, 8, 13, C-F, greater_than, 3.0
118 | #
119 | # These termination conditions will also be used to assign trajectory outcomes if
120 | # summarize_trajectories_to_screen is set to "yes".
121 |
122 | # description of fields:
123 | termination_condition : no_termination_conditions # bond_length, bond_angle, torsion
124 | # next fields = atom numbers (2, 3, or 4 fields)
125 | # description = one word
126 | # last two fields:
127 | # stop when the internal coordinate is greater_than, equal, or
128 | # less_than to the given number
129 |
130 | # NMR Calculations
131 | # Note: these options will be ignored if trajectory_type is set to "reaction".
132 |
133 | nmr_point_interval : 8 # how often in number of trajectory points to calculate NMR shieldings
134 | # (8 is recommended)
135 |
136 | shieldings_file : @blank # the file containing the NMR shieldings for the stationary point
137 | # at the NMR level of theory
138 | # (expected in working_directory/frequency_directory)
139 |
140 | gaussian_nmr_route_card : b3lyp/cc-pvdz # the route card to pass to Gaussian for an NMR job
141 | # place in quotes, all one line, use \n for new lines
142 | # Jprogdyn will add all other necessary keywords -- just put in
143 | # the level of theory/solvation, don't add NMR keyword
144 |
145 | gaussian_nmr_footer : @blank # stuff to put at the end of every NMR job (one line please)
146 |
147 | symmetry_groups : @blank # list of sets of symmetry-related atoms to average shieldings over
148 | # use a semicolon to specify multiple groups
149 |
150 |
151 | # Analysis Options
152 | # Note: these options will only be processed if job_type is set to "analysis."
153 | analysis_directory : analysis # path relative to working_directory where Jprogdyn will save
154 | # MOLDEN movies to
155 |
156 | make_molden_movies : yes # if "yes" will make movies of each trajectory and save it to
157 | # analysis_directory (any existing movies will be overwritten)
158 | # files will be named checkpoint_filename.traj
159 |
160 | summarize_trajectories_to_screen : yes # if "yes" parse the list of analysis_coordinates below,
161 | # analyze each trajectory, and print the report to the screen
162 |
163 | summary_interval : 100 # when printing out a report of the trajectories to the screen,
164 | # how often to print out updates, given in trajectory points
165 | # recommended: 20
166 |
167 | # place multiple analysis_coordinate entries on separate lines
168 | # to use no analysis coordinates, write a single line:
169 | # analysis_coordinate : no_analysis_coordinates
170 | # description of fields:
171 | analysis_coordinate : bond_length, 8, 13, C-F # bond_length, bond_angle, torsion
172 | analysis_coordinate : bond_length, 8, 17, C-Cl # next fields = atom numbers (2, 3, or 4 fields)
173 | # description = one word
174 |
175 | write_analysis_csv : yes # if "yes", write a comma-separated file containing the
176 | # above coordinates as a function of time for each trajectory
177 | # to a analysis_directory/checkpoint_filename.dat
178 | # (this means one csv file per trajectory)
179 |
--------------------------------------------------------------------------------