1 /*
2  * Copyright (c) 2015 John May <jwmay@users.sf.net>
3  *
4  * Contact: cdk-devel@lists.sourceforge.net
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or (at
9  * your option) any later version. All we ask is that proper credit is given
10  * for our work, which includes - but is not limited to - adding the above
11  * copyright notice to the beginning of your source code files, and to any
12  * copyright notice that you may distribute with programs based on this work.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17  * 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 U
22  */
23 package org.openscience.cdk.forcefield.mmff;
24 
25 import org.junit.AfterClass;
26 import org.junit.BeforeClass;
27 import org.junit.Test;
28 import org.openscience.cdk.exception.InvalidSmilesException;
29 import org.openscience.cdk.interfaces.IAtomContainer;
30 import org.openscience.cdk.silent.SilentChemObjectBuilder;
31 import org.openscience.cdk.smiles.SmilesParser;
32 import org.openscience.cdk.tools.manipulator.AtomContainerManipulator;
33 
34 import static org.hamcrest.CoreMatchers.is;
35 import static org.hamcrest.MatcherAssert.assertThat;
36 import static org.junit.Assert.assertArrayEquals;
37 import static org.junit.Assert.assertEquals;
38 import static org.junit.Assert.assertFalse;
39 import static org.junit.Assert.assertTrue;
40 
41 /**
42  * @author John May
43  */
44 public class MmffTest {
45 
46     private static SmilesParser smipar = null;
47     private static Mmff         mmff   = null;
48 
setUp()49     @BeforeClass public static void setUp() {
50         smipar = new SmilesParser(SilentChemObjectBuilder.getInstance());
51         mmff = new Mmff();
52     }
53 
tearDown()54     @AfterClass public static void tearDown() {
55         smipar = null;
56         mmff = null;
57     }
58 
tetrazoleAnion()59     @Test public void tetrazoleAnion() throws InvalidSmilesException {
60         IAtomContainer mol = loadSmi("[N-]1N=CN=N1");
61         assertTrue(mmff.assignAtomTypes(mol));
62         assertAtomTypes(mol, "N5M", "N5M", "C5", "N5M", "N5M", "HC");
63         assertTrue(mmff.partialCharges(mol));
64         assertPartialCharges(mol, -0.25, -0.5875, 0.525, -0.5875, -0.25, 0.15);
65         assertPartialChargeSum(mol, -1);
66     }
67 
tetrazole()68     @Test public void tetrazole() throws InvalidSmilesException {
69         IAtomContainer mol = loadSmi("N1N=CN=N1");
70         assertTrue(mmff.assignAtomTypes(mol));
71         assertAtomTypes(mol, "NPYL", "N5A", "C5B", "N5B", "N5A", "HPYL", "HC");
72         assertTrue(mmff.partialCharges(mol));
73         assertPartialCharges(mol, 0.566, -0.7068, 0.366, -0.2272, -0.418, 0.27, 0.15);
74         assertPartialChargeSum(mol, 0);
75     }
76 
untypedAtom()77     @Test public void untypedAtom() throws InvalidSmilesException {
78         IAtomContainer mol = loadSmi("[Se]C1C=CC=C1");
79         assertFalse(mmff.assignAtomTypes(mol));
80         assertAtomTypes(mol, "UNK", "CR", "C=C", "C=C", "C=C", "C=C", "HC", "HC", "HC", "HC", "HC");
81         assertTrue(mmff.partialCharges(mol));
82         assertPartialCharges(mol, 0.0, 0.2764, -0.2882, -0.15, -0.15, -0.2882, 0.0, 0.15, 0.15, 0.15, 0.15);
83         assertPartialChargeSum(mol, 0);
84     }
85 
clearProps()86     @Test public void clearProps() throws InvalidSmilesException {
87         IAtomContainer mol = loadSmi("o1cccc1");
88         int sizeBefore = mol.getProperties().size();
89         assertTrue(mmff.assignAtomTypes(mol));
90         assertTrue(mmff.partialCharges(mol));
91         mmff.clearProps(mol);
92         assertThat(mol.getProperties().size(), is(sizeBefore));
93     }
94 
nitrobenzeneCovalent()95     @Test public void nitrobenzeneCovalent() throws InvalidSmilesException {
96         IAtomContainer mol = loadSmi("c1ccccc1N(=O)=O");
97         assertTrue(mmff.assignAtomTypes(mol));
98         assertAtomTypes(mol, "CB", "CB", "CB", "CB", "CB", "CB", "NO2", "O2N", "O2N", "HC", "HC", "HC", "HC", "HC");
99         assertTrue(mmff.partialCharges(mol));
100         assertPartialCharges(mol, -0.15, -0.15, -0.15, -0.15, -0.15, 0.133, 0.907, -0.52, -0.52, 0.15, 0.15, 0.15, 0.15, 0.15);
101         assertPartialChargeSum(mol, 0);
102     }
103 
nitrobenzeneChargeSeparated()104     @Test public void nitrobenzeneChargeSeparated() throws InvalidSmilesException {
105         IAtomContainer mol = loadSmi("c1ccccc1[N+](-[O-])=O");
106         assertTrue(mmff.assignAtomTypes(mol));
107         assertAtomTypes(mol, "CB", "CB", "CB", "CB", "CB", "CB", "NO2", "O2N", "O2N", "HC", "HC", "HC", "HC", "HC");
108         assertTrue(mmff.partialCharges(mol));
109         assertPartialCharges(mol, -0.15, -0.15, -0.15, -0.15, -0.15, 0.133, 0.907, -0.52, -0.52, 0.15, 0.15, 0.15, 0.15, 0.15);
110         assertPartialChargeSum(mol, 0);
111     }
112 
113     /* TABLE V - CH3OH */
methanol()114     @Test public void methanol() throws Exception {
115         IAtomContainer mol = loadSmi("CO");
116         assertTrue(mmff.assignAtomTypes(mol));
117         assertTrue(mmff.partialCharges(mol));
118         assertPartialCharges(mol,
119                              0.28, -0.68, 0.0, 0.0, 0.0, 0.4);
120         assertPartialChargeSum(mol, 0);
121     }
122 
123     /* TABLE V - CH3NH2 */
methylamine()124     @Test public void methylamine() throws Exception {
125         IAtomContainer mol = loadSmi("CN");
126         assertTrue(mmff.assignAtomTypes(mol));
127         assertTrue(mmff.partialCharges(mol));
128         assertPartialCharges(mol,
129                              0.27, -0.99, 0.0, 0.0, 0.0, 0.36, 0.36);
130         assertPartialChargeSum(mol, 0);
131     }
132 
133     /* TABLE V - CH3CN */
acetonitrile()134     @Test public void acetonitrile() throws Exception {
135         IAtomContainer mol = loadSmi("CC#N");
136         assertTrue(mmff.assignAtomTypes(mol));
137         assertTrue(mmff.partialCharges(mol));
138         assertPartialCharges(mol,
139                              0.2, 0.357, -0.557, 0.0, 0.0, 0.0);
140         assertPartialChargeSum(mol, 0);
141     }
142 
143     /* TABLE V - CH3OCH3 */
dimethylether()144     @Test public void dimethylether() throws Exception {
145         IAtomContainer mol = loadSmi("COC");
146         assertTrue(mmff.assignAtomTypes(mol));
147         assertTrue(mmff.partialCharges(mol));
148         assertPartialCharges(mol,
149                              0.28, -0.56, 0.28, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
150         assertPartialChargeSum(mol, 0);
151     }
152 
153     /* TABLE V - CH3SH */
methanethiol()154     @Test public void methanethiol() throws Exception {
155         IAtomContainer mol = loadSmi("CS");
156         assertTrue(mmff.assignAtomTypes(mol));
157         assertTrue(mmff.partialCharges(mol));
158         assertPartialCharges(mol,
159                              0.23, -0.41, 0.0, 0.0, 0.0, 0.18);
160         assertPartialChargeSum(mol, 0);
161     }
162 
163     /* TABLE V - CH3Cl */
chloromethane()164     @Test public void chloromethane() throws Exception {
165         IAtomContainer mol = loadSmi("CCl");
166         assertTrue(mmff.assignAtomTypes(mol));
167         assertTrue(mmff.partialCharges(mol));
168         assertPartialCharges(mol,
169                              0.29, -0.29, 0.0, 0.0, 0.0);
170         assertPartialChargeSum(mol, 0);
171     }
172 
173     /* TABLE V - C2H6 */
ethane()174     @Test public void ethane() throws Exception {
175         IAtomContainer mol = loadSmi("CC");
176         assertTrue(mmff.assignAtomTypes(mol));
177         assertTrue(mmff.partialCharges(mol));
178         assertPartialCharges(mol,
179                              0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
180         assertPartialChargeSum(mol, 0);
181     }
182 
183     /* TABLE V - CH3CONH2 (note wrong formula) */
acetamide()184     @Test public void acetamide() throws Exception {
185         IAtomContainer mol = loadSmi("O=C(N)C");
186         assertTrue(mmff.assignAtomTypes(mol));
187         assertTrue(mmff.partialCharges(mol));
188         assertPartialCharges(mol,
189                              -0.57, 0.569, -0.8, 0.061, 0.37, 0.37, 0.0, 0.0, 0.0);
190         assertPartialChargeSum(mol, 0);
191     }
192 
193     /* TABLE V - CH3COOH */
aceticAcid()194     @Test public void aceticAcid() throws Exception {
195         IAtomContainer mol = loadSmi("CC(O)=O");
196         assertTrue(mmff.assignAtomTypes(mol));
197         assertTrue(mmff.partialCharges(mol));
198         assertPartialCharges(mol,
199                              0.061, 0.659, -0.65, -0.57, 0.0, 0.0, 0.0, 0.5);
200         assertPartialChargeSum(mol, 0);
201     }
202 
203     /* TABLE V - (CH3)2CO */
acetone()204     @Test public void acetone() throws Exception {
205         IAtomContainer mol = loadSmi("CC(=O)C");
206         assertTrue(mmff.assignAtomTypes(mol));
207         assertTrue(mmff.partialCharges(mol));
208         assertPartialCharges(mol,
209                              0.061, 0.447, -0.57, 0.061, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
210         assertPartialChargeSum(mol, 0);
211     }
212 
213     /* TABLE V - CH3COOCH3  */
methylacetate()214     @Test public void methylacetate() throws Exception {
215         IAtomContainer mol = loadSmi("O=C(OC)C");
216         assertTrue(mmff.assignAtomTypes(mol));
217         assertTrue(mmff.partialCharges(mol));
218         assertPartialCharges(mol,
219                              -0.57, 0.659, -0.43, 0.28, 0.061, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
220         assertPartialChargeSum(mol, 0);
221     }
222 
223     /* TABLE V - C6H6 */
benzene()224     @Test public void benzene() throws Exception {
225         IAtomContainer mol = loadSmi("c1ccccc1");
226         assertTrue(mmff.assignAtomTypes(mol));
227         assertTrue(mmff.partialCharges(mol));
228         assertPartialCharges(mol,
229                              -0.15, -0.15, -0.15, -0.15, -0.15, -0.15, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15);
230         assertPartialChargeSum(mol, 0);
231     }
232 
233     /* TABLE V - C5H5N */
pyridine()234     @Test public void pyridine() throws Exception {
235         IAtomContainer mol = loadSmi("C1=CC=NC=C1");
236         assertTrue(mmff.assignAtomTypes(mol));
237         assertTrue(mmff.partialCharges(mol));
238         assertPartialCharges(mol,
239                              -0.15, -0.15, 0.16, -0.62, 0.16, -0.15, 0.15, 0.15, 0.15, 0.15, 0.15);
240         assertPartialChargeSum(mol, 0);
241     }
242 
243     /* TABLE V - C6H5NH2 */
aniline()244     @Test public void aniline() throws Exception {
245         IAtomContainer mol = loadSmi("C1=CC=C(N)C=C1");
246         assertTrue(mmff.assignAtomTypes(mol));
247         assertTrue(mmff.partialCharges(mol));
248         assertPartialCharges(mol,
249                              -0.15, -0.15, -0.15, 0.1, -0.9, -0.15, -0.15, 0.15, 0.15, 0.15, 0.4, 0.4, 0.15, 0.15);
250         assertPartialChargeSum(mol, 0);
251     }
252 
253     /* TABLE V - imidazole */
imidazole()254     @Test public void imidazole() throws Exception {
255         IAtomContainer mol = loadSmi("C=1NC=NC1");
256         assertTrue(mmff.assignAtomTypes(mol));
257         assertTrue(mmff.partialCharges(mol));
258         assertPartialCharges(mol,
259                              -0.3016, 0.0332, 0.0365, -0.5653, 0.0772, 0.15, 0.27, 0.15, 0.15);
260         assertPartialChargeSum(mol, 0);
261     }
262 
263     /* TABLE V - H2O */
water()264     @Test public void water() throws Exception {
265         IAtomContainer mol = loadSmi("O");
266         assertTrue(mmff.assignAtomTypes(mol));
267         assertTrue(mmff.partialCharges(mol));
268         assertPartialCharges(mol,
269                              -0.86, 0.43, 0.43);
270         assertPartialChargeSum(mol, 0);
271     }
272 
273     /* TABLE V - CH3CO2- */
acetate()274     @Test public void acetate() throws Exception {
275         IAtomContainer mol = loadSmi("CC([O-])=O");
276         assertTrue(mmff.assignAtomTypes(mol));
277         assertTrue(mmff.partialCharges(mol));
278         assertPartialCharges(mol,
279                              -0.106, 0.906, -0.9, -0.9, 0.0, 0.0, 0.0);
280         assertPartialChargeSum(mol, -1);
281     }
282 
283     /* TABLE V - CH3NH3(+)  */
methanaminium()284     @Test public void methanaminium() throws Exception {
285         IAtomContainer mol = loadSmi("C[NH3+]");
286         assertTrue(mmff.assignAtomTypes(mol));
287         assertTrue(mmff.partialCharges(mol));
288         assertPartialCharges(mol,
289                              0.503, -0.853, 0.0, 0.0, 0.0, 0.45, 0.45, 0.45);
290         assertPartialChargeSum(mol, +1);
291     }
292 
293     /* TABLE V - Imidazolium(+) */
imidazolium()294     @Test public void imidazolium() throws Exception {
295         IAtomContainer mol = loadSmi("[nH+]1c[nH]cc1");
296         assertTrue(mmff.assignAtomTypes(mol));
297         assertTrue(mmff.partialCharges(mol));
298         assertPartialCharges(mol,
299                              -0.7, 0.65, -0.7, 0.2, 0.2, 0.45, 0.15, 0.45, 0.15, 0.15);
300         assertPartialChargeSum(mol, +1);
301     }
302 
303     /* TABLE V - (-)O2C(CH2)6NH3(+) */
_7aminoheptanoicAcid()304     @Test public void _7aminoheptanoicAcid() throws Exception {
305         IAtomContainer mol = loadSmi("[NH3+]CCCCCCC([O-])=O");
306         assertTrue(mmff.assignAtomTypes(mol));
307         assertTrue(mmff.partialCharges(mol));
308         assertPartialCharges(mol,
309                              -0.853, 0.503, 0.0, 0.0, 0.0, 0.0, -0.106, 0.906, -0.9, -0.9, 0.45, 0.45, 0.45, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
310         assertPartialChargeSum(mol, 0);
311     }
312 
ethoxyethane()313     @Test public void ethoxyethane() throws Exception {
314         IAtomContainer mol = loadSmi("CCOCC");
315         assertTrue(mmff.assignAtomTypes(mol));
316         assertTrue(mmff.partialCharges(mol));
317         assertPartialCharges(mol,
318                              0.0, 0.28, -0.56, 0.28, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
319         assertPartialChargeSum(mol, 0);
320     }
321 
loadSmi(String smi)322     private IAtomContainer loadSmi(String smi) throws InvalidSmilesException {
323         IAtomContainer mol = smipar.parseSmiles(smi);
324         AtomContainerManipulator.convertImplicitToExplicitHydrogens(mol);
325         return mol;
326     }
327 
328     /* [PO4]3- */
phosphate()329     @Test public void phosphate() throws Exception {
330         IAtomContainer mol = loadSmi("[O-]P([O-])([O-])=O");
331         assertTrue(mmff.assignAtomTypes(mol));
332         assertTrue(mmff.partialCharges(mol));
333         assertPartialCharges(mol,
334                              -1.075, 1.3, -1.075, -1.075, -1.075);
335     }
336 
337     /* [HOPO3]2- */
hydrogenPhosphate()338     @Test public void hydrogenPhosphate() throws Exception {
339         IAtomContainer mol = loadSmi("OP([O-])([O-])=O");
340         assertTrue(mmff.assignAtomTypes(mol));
341         assertTrue(mmff.partialCharges(mol));
342         assertPartialCharges(mol,
343                              -0.7712, 1.3712, -1.033, -1.033, -1.033, 0.5);
344     }
345 
346     /* [H2OPO3]- */
dihydrogenPhosphate()347     @Test public void dihydrogenPhosphate() throws Exception {
348         IAtomContainer mol = loadSmi("OP([O-])(O)=O");
349         assertTrue(mmff.assignAtomTypes(mol));
350         assertTrue(mmff.partialCharges(mol));
351         assertPartialCharges(mol,
352                              -0.7712, 1.4424, -0.95, -0.7712, -0.95, 0.5, 0.5);
353     }
354 
355     /* H3OPO3 */
phosphoricAcid()356     @Test public void phosphoricAcid() throws Exception {
357         IAtomContainer mol = loadSmi("OP(O)(O)=O");
358         assertTrue(mmff.assignAtomTypes(mol));
359         assertTrue(mmff.partialCharges(mol));
360         assertPartialCharges(mol,
361                              -0.7712, 1.514, -0.7712, -0.7712, -0.7, 0.5, 0.5, 0.5);
362     }
363 
364     /* SEYWUO - validation suite showing positive charge charging */
SEYWUO()365     @Test public void SEYWUO() throws Exception {
366         IAtomContainer mol = loadSmi("[H]OC(=S)[N-][N+]1=C(N([H])[H])C([H])([H])N([H])C1=O");
367         assertTrue(mmff.assignAtomTypes(mol));
368         assertAtomTypes(mol,
369                         "HOCS", "OC=S", "C=S", "S=C", "NM", "NCN+", "CNN+", "NCN+", "HNN+", "HNN+", "CR", "HC", "HC", "NC=O", "HNCO", "CONN", "O=CN");
370         assertTrue(mmff.effectiveCharges(mol));
371         assertPartialCharges(mol,
372                              0.0, 0.0, -0.25, 0.0, -0.5, 0.25, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
373         assertTrue(mmff.partialCharges(mol));
374         assertPartialCharges(mol,
375                              0.4, -0.55, 0.31, -0.38, -0.179, -0.8364, 0.6038, -0.7544, 0.45, 0.45, 0.4051, 0.0, 0.0, -0.7301, 0.37, 1.011, -0.57);
376     }
377 
assertAtomTypes(IAtomContainer mol, String... expected)378     private void assertAtomTypes(IAtomContainer mol, String... expected) {
379         String[] actual = new String[mol.getAtomCount()];
380         for (int i = 0; i < mol.getAtomCount(); i++)
381             actual[i] = mol.getAtom(i).getAtomTypeName();
382         assertArrayEquals(expected, actual);
383     }
384 
assertPartialCharges(IAtomContainer mol, double... expected)385     private void assertPartialCharges(IAtomContainer mol, double... expected) {
386         double[] actual = new double[mol.getAtomCount()];
387         for (int i = 0; i < mol.getAtomCount(); i++)
388             actual[i] = mol.getAtom(i).getCharge();
389         assertArrayEquals(expected, actual, 0.001);
390     }
391 
assertPartialChargeSum(IAtomContainer mol, double expected)392     private void assertPartialChargeSum(IAtomContainer mol, double expected) {
393         double actual = 0;
394         for (int i = 0; i < mol.getAtomCount(); i++)
395             actual += mol.getAtom(i).getCharge();
396         assertEquals("Unexpected partial charge sum",
397                      expected, actual, 0.001);
398     }
399 }
400