/* $RCSfile$ * $Author$ * $Date$ * $Revision$ * * Copyright (C) 2003-2007 The Jmol Development Team (v. 1.1.2.2) * Copyright (C) 2003-2007 The Chemistry Development Kit (CDK) project * * 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; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.util.StringTokenizer; import javax.vecmath.Point3d; import javax.vecmath.Vector3d; import org.openscience.cdk.CDKConstants; import org.openscience.cdk.annotations.TestClass; import org.openscience.cdk.annotations.TestMethod; import org.openscience.cdk.config.IsotopeFactory; import org.openscience.cdk.exception.CDKException; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IChemFile; import org.openscience.cdk.interfaces.IChemModel; import org.openscience.cdk.interfaces.IChemObject; import org.openscience.cdk.interfaces.IChemSequence; import org.openscience.cdk.interfaces.ICrystal; import org.openscience.cdk.io.formats.IResourceFormat; import org.openscience.cdk.io.formats.VASPFormat; import org.openscience.cdk.math.FortranFormat; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; /** * Read output files generated with the VASP software. * * @cdk.module extra * @cdk.githash * * @author Fabian Dortu <Fabian.Dortu@wanadoo.be> */ @TestClass("org.openscience.cdk.io.VSPReaderTest") public class VASPReader extends DefaultChemObjectReader { private static ILoggingTool logger = LoggingToolFactory.createLoggingTool(VASPReader.class); // This variable is used to parse the input file protected StringTokenizer st = new StringTokenizer("", "");; protected String fieldVal; protected int repVal = 0; protected BufferedReader inputBuffer; // VASP VARIABLES int natom = 1; int ntype = 1; double acell[] = new double[3]; double[][] rprim = new double[3][3]; String info = ""; String line; String[] anames; //size is ntype. Contains the names of the atoms int natom_type[]; //size is natom. Contain the atomic number String representation; // "Direct" only so far /** * Creates a new <code>VASPReader</code> instance. * * @param input a <code>Reader</code> value */ public VASPReader(Reader input) { if (input instanceof BufferedReader) { this.inputBuffer = (BufferedReader)input; } else { this.inputBuffer = new BufferedReader(input); } } public VASPReader(InputStream input) { this(new InputStreamReader(input)); } public VASPReader() { this(new StringReader("")); } @TestMethod("testGetFormat") public IResourceFormat getFormat() { return VASPFormat.getInstance(); } @TestMethod("testSetReader_Reader") public void setReader(Reader input) throws CDKException { if (input instanceof BufferedReader) { this.inputBuffer = (BufferedReader)input; } else { this.inputBuffer = new BufferedReader(input); } } @TestMethod("testSetReader_InputStream") public void setReader(InputStream input) throws CDKException { setReader(new InputStreamReader(input)); } @TestMethod("testAccepts") public boolean accepts(Class classObject) { Class[] interfaces = classObject.getInterfaces(); for (int i=0; i<interfaces.length; i++) { if (IChemFile.class.equals(interfaces[i])) return true; } return false; } public IChemObject read(IChemObject object) throws CDKException { if (object instanceof IChemFile) { IChemFile cf = (IChemFile)object; try { cf = readChemFile(cf); } catch (IOException exception) { String error = "Input/Output error while reading from input: " + exception.getMessage(); logger.error(error); logger.debug(exception); throw new CDKException(error, exception); } return cf; } else { throw new CDKException("Only supported is reading of ChemFile."); } } private IChemFile readChemFile(IChemFile file) throws CDKException, IOException { IChemSequence seq = readChemSequence(file.getBuilder().newChemSequence()); file.addChemSequence(seq); return file; } private IChemSequence readChemSequence(IChemSequence sequence) throws CDKException, IOException { IChemModel chemModel = sequence.getBuilder().newChemModel(); ICrystal crystal = null; // Get the info line (first token of the first line) inputBuffer.mark(255); info = nextVASPToken(false); //logger.debug(info); inputBuffer.reset(); // Get the number of different atom "NCLASS=X" inputBuffer.mark(255); nextVASPTokenFollowing("NCLASS"); ntype = Integer.parseInt(fieldVal); //logger.debug("NCLASS= " + ntype); inputBuffer.reset(); // Get the different atom names anames = new String[ntype]; nextVASPTokenFollowing("ATOM"); for(int i = 0; i < ntype; i++) { anames[i] = fieldVal; nextVASPToken(false); } // Get the number of atom of each type int[] natom_type = new int[ntype]; natom = 0; for(int i = 0; i < ntype; i++) { natom_type[i] = Integer.parseInt(fieldVal); nextVASPToken(false); natom = natom + natom_type[i]; } // Get the representation type of the primitive vectors // only "Direct" is recognize now. representation = fieldVal; if(representation.equals("Direct")) { logger.info("Direct representation"); // DO NOTHING } else { throw new CDKException("This VASP file is not supported. Please contact the Jmol developpers"); } while(nextVASPToken(false) != null) { logger.debug("New crystal started..."); crystal = sequence.getBuilder().newCrystal(); chemModel = sequence.getBuilder().newChemModel(); // Get acell for(int i=0; i<3; i++) { acell[i] = FortranFormat.atof(fieldVal); // all the same FIX? } // Get primitive vectors for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { nextVASPToken(false); rprim[i][j] = FortranFormat.atof(fieldVal); } } // Get atomic position int[] atomType = new int[natom]; double[][] xred = new double[natom][3]; int atomIndex=0; for(int i = 0; i < ntype; i++) { for(int j = 0; j < natom_type[i] ; j++) { try { atomType[atomIndex] = IsotopeFactory.getInstance(sequence.getBuilder()). getElement(anames[i]).getAtomicNumber(); } catch (Exception exception) { throw new CDKException("Could not determine atomic number!", exception); } logger.debug("aname: " + anames[i]); logger.debug("atomType: " + atomType[atomIndex]); nextVASPToken(false); xred[atomIndex][0] = FortranFormat.atof(fieldVal); nextVASPToken(false); xred[atomIndex][1] = FortranFormat.atof(fieldVal); nextVASPToken(false); xred[atomIndex][2] = FortranFormat.atof(fieldVal); atomIndex = atomIndex+1; // FIXME: store atom } } crystal.setA(new Vector3d(rprim[0][0]*acell[0], rprim[0][1]*acell[0], rprim[0][2]*acell[0])); crystal.setB(new Vector3d(rprim[1][0]*acell[1], rprim[1][1]*acell[1], rprim[1][2]*acell[1])); crystal.setC(new Vector3d(rprim[2][0]*acell[2], rprim[2][1]*acell[2], rprim[2][2]*acell[2])); for (int i=0; i<atomType.length; i++) { String symbol = "Du"; try { symbol = IsotopeFactory.getInstance(sequence.getBuilder()). getElement(atomType[i]).getSymbol(); } catch (Exception exception) { throw new CDKException("Could not determine element symbol!", exception); } IAtom atom = sequence.getBuilder().newAtom(symbol); atom.setAtomicNumber(atomType[i]); // convert fractional to cartesian double[] frac = new double[3]; frac[0] = xred[i][0]; frac[1] = xred[i][1]; frac[2] = xred[i][2]; atom.setFractionalPoint3d(new Point3d(frac[0], frac[1], frac[2])); crystal.addAtom(atom); } crystal.setProperty(CDKConstants.REMARK, info); chemModel.setCrystal(crystal); logger.info("New Frame set!"); sequence.addChemModel(chemModel); } //end while return sequence; } /** * Find the next token of an VASP file. * ABINIT tokens are words separated by space(s). Characters * following a "#" are ignored till the end of the line. * * @return a <code>String</code> value * @exception IOException if an error occurs */ public String nextVASPToken(boolean newLine) throws IOException { String line; if (newLine) { // We ignore the end of the line and go to the following line if (inputBuffer.ready()) { line = inputBuffer.readLine(); st = new StringTokenizer(line, " =\t"); } } while (!st.hasMoreTokens() && inputBuffer.ready()) { line = inputBuffer.readLine(); st = new StringTokenizer(line, " =\t"); } if (st.hasMoreTokens()) { fieldVal = st.nextToken(); if (fieldVal.startsWith("#")) { nextVASPToken(true); } } else { fieldVal = null; } return this.fieldVal; } //end nextVASPToken(boolean newLine) /** * Find the next token of a VASP file begining * with the *next* line. */ public String nextVASPTokenFollowing(String string) throws IOException { int index; String line; while (inputBuffer.ready()) { line = inputBuffer.readLine(); index = line.indexOf(string); if (index > 0) { index = index + string.length(); line = line.substring(index); st = new StringTokenizer(line, " =\t"); while(!st.hasMoreTokens() && inputBuffer.ready()) { line = inputBuffer.readLine(); st = new StringTokenizer(line, " =\t"); } if (st.hasMoreTokens()) { fieldVal = st.nextToken(); } else { fieldVal = null; } break; } } return fieldVal; } //end nextVASPTokenFollowing(String string) @TestMethod("testClose") public void close() throws IOException { inputBuffer.close(); } }