/* $Revision$ $Author$ $Date$
*
* Copyright (C) 2003-2008 Egon Willighagen <egonw@sci.kun.nl>
*
* Contact: cdk-devel@lists.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.openscience.cdk.io.program;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.vecmath.Point3d;
import org.openscience.cdk.annotations.TestClass;
import org.openscience.cdk.annotations.TestMethod;
import org.openscience.cdk.exception.CDKException;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IChemObject;
import org.openscience.cdk.interfaces.IMolecule;
import org.openscience.cdk.io.DefaultChemObjectWriter;
import org.openscience.cdk.io.formats.GaussianInputFormat;
import org.openscience.cdk.io.formats.IResourceFormat;
import org.openscience.cdk.io.setting.BooleanIOSetting;
import org.openscience.cdk.io.setting.IOSetting;
import org.openscience.cdk.io.setting.IntegerIOSetting;
import org.openscience.cdk.io.setting.OptionIOSetting;
import org.openscience.cdk.io.setting.StringIOSetting;
/**
* File writer thats generates input files for Gaussian calculation
* jobs. It was tested with Gaussian98.
*
* @cdk.module io
* @cdk.githash
*
* @author Egon Willighagen <egonw@sci.kun.nl>
*
* @cdk.keyword Gaussian (tm), input file
*/
@TestClass("org.openscience.cdk.io.program.GaussianInputWriterTest")
public class GaussianInputWriter extends DefaultChemObjectWriter {
static BufferedWriter writer;
IOSetting method;
IOSetting basis;
IOSetting comment;
IOSetting command;
IOSetting memory;
BooleanIOSetting shell;
IntegerIOSetting proccount;
BooleanIOSetting usecheckpoint;
/**
* Constructs a new writer that produces input files to run a
* Gaussian QM job.
*/
public GaussianInputWriter(Writer out) {
try {
if (out instanceof BufferedWriter) {
writer = (BufferedWriter)out;
} else {
writer = new BufferedWriter(out);
}
} catch (Exception exc) {
}
initIOSettings();
}
public GaussianInputWriter(OutputStream output) {
this(new OutputStreamWriter(output));
}
public GaussianInputWriter() {
this(new StringWriter());
}
@TestMethod("testGetFormat")
public IResourceFormat getFormat() {
return GaussianInputFormat.getInstance();
}
public void setWriter(Writer out) throws CDKException {
if (out instanceof BufferedWriter) {
writer = (BufferedWriter)out;
} else {
writer = new BufferedWriter(out);
}
}
public void setWriter(OutputStream output) throws CDKException {
setWriter(new OutputStreamWriter(output));
}
@TestMethod("testClose")
public void close() throws IOException {
writer.close();
}
@TestMethod("testAccepts")
public boolean accepts(Class classObject) {
if (IMolecule.class.isInstance(classObject)) return true;
return false;
}
@TestMethod("testWrite")
public void write(IChemObject object) throws CDKException {
if (object instanceof IMolecule) {
try {
writeMolecule((IMolecule)object);
} catch(Exception ex) {
throw new CDKException("Error while writing Gaussian input file: " + ex.getMessage(), ex);
}
} else {
throw new CDKException("GaussianInputWriter only supports output of Molecule classes.");
}
}
/**
* Writes a molecule for input for Gaussian.
*/
public void writeMolecule(IMolecule mol) throws IOException {
customizeJob();
// write extra statements
if (proccount.getSettingValue() > 1) {
writer.write("%nprocl=" + proccount.getSettingValue());
writer.newLine();
}
if (!memory.getSetting().equals("unset")) {
writer.write("%Mem=" + memory.getSetting());
writer.newLine();
}
if (usecheckpoint.isSet()) {
if (mol.getID() != null && mol.getID().length() > 0) {
writer.write("%chk=" + mol.getID() + ".chk");
} else {
// force different file names
writer.write("%chk=" + System.currentTimeMillis() + ".chk");
}
writer.newLine();
}
// write the command line
writer.write("# " + method.getSetting() +
"/" + basis.getSetting() +
" ");
String commandString = command.getSetting();
if (commandString.equals("energy calculation")) {
// ok, no special command needed
} else if (commandString.equals("geometry optimization")) {
writer.write("opt");
} else if (commandString.equals("IR frequency calculation")) {
writer.write("freq");
} else if (commandString.equals("IR frequency calculation (with Raman)")) {
writer.write("freq=noraman");
} else {
// assume that user knows what he's doing
writer.write(commandString);
}
writer.newLine();
// next line is empty
writer.newLine();
// next line is comment
writer.write(comment.getSetting());
writer.newLine();
// next line is empty
writer.newLine();
/* next line contains two digits
* the first is the total charge
* the second is boolean indicating:
* 0 = open shell
* 1 = closed shell
*/
writer.write("0 "); // FIXME: should write total charge of molecule
if (shell.isSet()) {
writer.write("0");
} else {
writer.write("1");
}
writer.newLine();
// then come all the atoms.
// Loop through the atoms and write them out:
Iterator<IAtom> atoms = mol.atoms().iterator();
while (atoms.hasNext()) {
IAtom a = atoms.next();
String st = a.getSymbol();
// export Eucledian coordinates (indicated by the 0)
st = st + " 0 ";
// export the 3D coordinates
Point3d p3 = a.getPoint3d();
if (p3 != null) {
st = st + new Double(p3.x).toString() + " "
+ new Double(p3.y).toString() + " "
+ new Double(p3.z).toString();
}
writer.write(st, 0, st.length());
writer.newLine();
}
// G98 expects an empty line at the end
writer.newLine();
}
private void initIOSettings() {
List<String> basisOptions = new ArrayList<String>();
basisOptions.add("6-31g");
basisOptions.add("6-31g*");
basisOptions.add("6-31g(d)");
basisOptions.add("6-311g");
basisOptions.add("6-311+g**");
basis = new OptionIOSetting("Basis", IOSetting.MEDIUM,
"Which basis set do you want to use?", basisOptions, "6-31g");
List<String> methodOptions = new ArrayList<String>();
methodOptions.add("rb3lyp");
methodOptions.add("b3lyp");
methodOptions.add("rhf");
method = new OptionIOSetting("Method", IOSetting.MEDIUM,
"Which method do you want to use?", methodOptions, "b3lyp");
List<String> commandOptions = new ArrayList<String>();
commandOptions.add("energy calculation");
commandOptions.add("geometry optimization");
commandOptions.add("IR frequency calculation");
commandOptions.add("IR frequency calculation (with Raman)");
command = new OptionIOSetting("Command", IOSetting.HIGH,
"What kind of job do you want to perform?", commandOptions,
"energy calculation");
comment = new StringIOSetting("Comment", IOSetting.LOW,
"What comment should be put in the file?",
"Created with CDK (http://cdk.sf.net/)");
memory = new StringIOSetting("Memory", IOSetting.LOW,
"How much memory do you want to use?",
"unset");
shell = new BooleanIOSetting("OpenShell", IOSetting.MEDIUM,
"Should the calculation be open shell?",
"false");
proccount = new IntegerIOSetting("ProcessorCount", IOSetting.LOW,
"How many processors should be used by Gaussian?",
"1");
usecheckpoint = new BooleanIOSetting("UseCheckPointFile", IOSetting.LOW,
"Should a check point file be saved?",
"false");
}
private void customizeJob() {
fireIOSettingQuestion(basis);
fireIOSettingQuestion(method);
fireIOSettingQuestion(command);
fireIOSettingQuestion(comment);
fireIOSettingQuestion(shell);
fireIOSettingQuestion(proccount);
fireIOSettingQuestion(memory);
fireIOSettingQuestion(usecheckpoint);
}
public IOSetting[] getIOSettings() {
IOSetting[] settings = new IOSetting[8];
settings[0] = basis;
settings[1] = method;
settings[2] = command;
settings[3] = comment;
settings[4] = shell;
settings[5] = proccount;
settings[6] = usecheckpoint;
settings[7] = memory;
return settings;
}
}