1 /* Copyright (C) 2001-2007  The Chemistry Development Kit (CDK) project
2  *
3  * Contact: cdk-devel@lists.sourceforge.net
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License
7  * as published by the Free Software Foundation; either version 2.1
8  * of the License, or (at your option) any later version.
9  * All we ask is that proper credit is given for our work, which includes
10  * - but is not limited to - adding the above copyright notice to the beginning
11  * of your source code files, and to any copyright notice that you may distribute
12  * with programs based on this work.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  */
24 package org.openscience.cdk.io;
25 
26 import java.io.BufferedReader;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.InputStreamReader;
30 import java.io.Reader;
31 import java.io.StringReader;
32 import java.util.StringTokenizer;
33 
34 import javax.vecmath.Point3d;
35 
36 import org.openscience.cdk.CDKConstants;
37 import org.openscience.cdk.exception.CDKException;
38 import org.openscience.cdk.geometry.ZMatrixTools;
39 import org.openscience.cdk.interfaces.IAtom;
40 import org.openscience.cdk.interfaces.IAtomContainer;
41 import org.openscience.cdk.interfaces.IAtomContainerSet;
42 import org.openscience.cdk.interfaces.IChemFile;
43 import org.openscience.cdk.interfaces.IChemModel;
44 import org.openscience.cdk.interfaces.IChemObject;
45 import org.openscience.cdk.interfaces.IChemSequence;
46 import org.openscience.cdk.io.formats.IResourceFormat;
47 import org.openscience.cdk.io.formats.ZMatrixFormat;
48 
49 /**
50  * It reads Z matrices like in Gaussian input files. It seems that it cannot
51  * handle Z matrices where values are given via a stringID for which the value
52  * is given later.
53  *
54  * @cdk.module extra
55  * @cdk.githash
56  * @cdk.iooptions
57  *
58  * @cdk.keyword file format, Z-matrix
59  */
60 public class ZMatrixReader extends DefaultChemObjectReader {
61 
62     private BufferedReader input;
63 
64     /**
65      * Constructs a ZMatrixReader from a Reader that contains the
66      * data to be parsed.
67      *
68      * @param     input   Reader containing the data to read
69      */
ZMatrixReader(Reader input)70     public ZMatrixReader(Reader input) {
71         this.input = new BufferedReader(input);
72     }
73 
ZMatrixReader(InputStream input)74     public ZMatrixReader(InputStream input) {
75         this(new InputStreamReader(input));
76     }
77 
ZMatrixReader()78     public ZMatrixReader() {
79         this(new StringReader(""));
80     }
81 
82     @Override
getFormat()83     public IResourceFormat getFormat() {
84         return ZMatrixFormat.getInstance();
85     }
86 
87     @Override
setReader(Reader input)88     public void setReader(Reader input) throws CDKException {
89         if (input instanceof BufferedReader) {
90             this.input = (BufferedReader) input;
91         } else {
92             this.input = new BufferedReader(input);
93         }
94     }
95 
96     @Override
setReader(InputStream input)97     public void setReader(InputStream input) throws CDKException {
98         setReader(new InputStreamReader(input));
99     }
100 
101     @Override
accepts(Class<? extends IChemObject> classObject)102     public boolean accepts(Class<? extends IChemObject> classObject) {
103         return IChemFile.class.isAssignableFrom(classObject);
104     }
105 
106     /**
107      *  Returns a IChemObject of type object bye reading from
108      *  the input.
109      *
110      *  The function supports only reading of ChemFile's.
111      *
112      * @param     object  IChemObject that types the class to return.
113      * @throws    CDKException when a IChemObject is requested that cannot be read.
114      */
115     @Override
read(T object)116     public <T extends IChemObject> T read(T object) throws CDKException {
117         if (object instanceof IChemFile)
118             return (T) readChemFile((IChemFile) object);
119         else
120             throw new CDKException("Only ChemFile objects can be read.");
121     }
122 
123     /**
124      *  Private method that actually parses the input to read a ChemFile
125      *  object.
126      *
127      * @param file  the file to read from
128      * @return A ChemFile containing the data parsed from input.
129      */
readChemFile(IChemFile file)130     private IChemFile readChemFile(IChemFile file) {
131         IChemSequence chemSequence = file.getBuilder().newInstance(IChemSequence.class);
132 
133         int number_of_atoms;
134         StringTokenizer tokenizer;
135 
136         try {
137             String line = input.readLine();
138             while (line.startsWith("#"))
139                 line = input.readLine();
140             /*
141              * while (input.ready() && line != null) {
142              */
143             //        logger.debug("lauf");
144             // parse frame by frame
145             tokenizer = new StringTokenizer(line, "\t ,;");
146 
147             String token = tokenizer.nextToken();
148             number_of_atoms = Integer.parseInt(token);
149             String info = input.readLine();
150 
151             IChemModel chemModel = file.getBuilder().newInstance(IChemModel.class);
152             IAtomContainerSet setOfMolecules = file.getBuilder().newInstance(IAtomContainerSet.class);
153 
154             IAtomContainer m = file.getBuilder().newInstance(IAtomContainer.class);
155             m.setTitle(info);
156 
157             String[] types = new String[number_of_atoms];
158             double[] d = new double[number_of_atoms];
159             int[] d_atom = new int[number_of_atoms]; // Distances
160             double[] a = new double[number_of_atoms];
161             int[] a_atom = new int[number_of_atoms]; // Angles
162             double[] da = new double[number_of_atoms];
163             int[] da_atom = new int[number_of_atoms]; // Diederangles
164             //Point3d[] pos = new Point3d[number_of_atoms]; // calculated positions
165 
166             int i = 0;
167             while (i < number_of_atoms) {
168                 line = input.readLine();
169                 //          logger.debug("line:\""+line+"\"");
170                 if (line == null) break;
171                 if (line.startsWith("#")) {
172                     // skip comment in file
173                 } else {
174                     d[i] = 0d;
175                     d_atom[i] = -1;
176                     a[i] = 0d;
177                     a_atom[i] = -1;
178                     da[i] = 0d;
179                     da_atom[i] = -1;
180 
181                     tokenizer = new StringTokenizer(line, "\t ,;");
182                     int fields = tokenizer.countTokens();
183 
184                     if (fields < Math.min(i * 2 + 1, 7)) {
185                         // this is an error but cannot throw exception
186                     } else if (i == 0) {
187                         types[i] = tokenizer.nextToken();
188                         i++;
189                     } else if (i == 1) {
190                         types[i] = tokenizer.nextToken();
191                         d_atom[i] = Integer.valueOf(tokenizer.nextToken()) - 1;
192                         d[i] = Double.valueOf(tokenizer.nextToken());
193                         i++;
194                     } else if (i == 2) {
195                         types[i] = tokenizer.nextToken();
196                         d_atom[i] = Integer.valueOf(tokenizer.nextToken()) - 1;
197                         d[i] = Double.valueOf(tokenizer.nextToken());
198                         a_atom[i] = Integer.valueOf(tokenizer.nextToken()) - 1;
199                         a[i] = Double.valueOf(tokenizer.nextToken());
200                         i++;
201                     } else {
202                         types[i] = tokenizer.nextToken();
203                         d_atom[i] = Integer.valueOf(tokenizer.nextToken()) - 1;
204                         d[i] = Double.valueOf(tokenizer.nextToken());
205                         a_atom[i] = Integer.valueOf(tokenizer.nextToken()) - 1;
206                         a[i] = Double.valueOf(tokenizer.nextToken());
207                         da_atom[i] = Integer.valueOf(tokenizer.nextToken()) - 1;
208                         da[i] = Double.valueOf(tokenizer.nextToken());
209                         i++;
210                     }
211                 }
212             }
213 
214             // calculate cartesian coordinates
215             Point3d[] cartCoords = ZMatrixTools.zmatrixToCartesian(d, d_atom, a, a_atom, da, da_atom);
216 
217             for (i = 0; i < number_of_atoms; i++) {
218                 m.addAtom(file.getBuilder().newInstance(IAtom.class, types[i], cartCoords[i]));
219             }
220 
221             //        logger.debug("molecule:"+m);
222 
223             setOfMolecules.addAtomContainer(m);
224             chemModel.setMoleculeSet(setOfMolecules);
225             chemSequence.addChemModel(chemModel);
226             line = input.readLine();
227             file.addChemSequence(chemSequence);
228         } catch (IOException e) {
229             // should make some noise now
230             file = null;
231         }
232         return file;
233     }
234 
235     @Override
close()236     public void close() throws IOException {
237         input.close();
238     }
239 }
240