1 /**********************************************************************
2 cifspacegrouptest.cpp - Unit tests for to check if space group is being handled
3 properly in .cif format.
4 
5 Copyright (C) 2016 by Schrodinger Inc.
6 
7 This file is part of the Open Babel project.
8 For more information, see <http://openbabel.org/>
9 
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation version 2 of the License.
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 General Public License for more details.
18 ***********************************************************************/
19 
20 #include "obtest.h"
21 #include <openbabel/babelconfig.h>
22 #include <openbabel/mol.h>
23 #include <openbabel/obconversion.h>
24 #include <openbabel/generic.h>
25 
26 #include <string>
27 #include <algorithm>
28 
29 using namespace std;
30 using namespace OpenBabel;
31 
GetFilename(const std::string & filename)32 std::string static GetFilename(const std::string &filename)
33 {
34   string path = TESTDATADIR + filename;
35   return path;
36 }
37 
testSpaceGroupUniqueTransformations()38 void testSpaceGroupUniqueTransformations()
39 {
40   // See  https://github.com/openbabel/openbabel/pull/260
41   // also https://github.com/openbabel/openbabel/pull/255
42   OBConversion conv;
43   OBMol mol;
44   conv.SetInFormat("cif");
45   conv.ReadFile(&mol, GetFilename("test01.cif"));
46   OBUnitCell* pUC = (OBUnitCell*)mol.GetData(OBGenericDataType::UnitCell);
47   const SpaceGroup* pSG = pUC->GetSpaceGroup();
48   SpaceGroup* sg = new SpaceGroup(*pSG);
49   pSG = SpaceGroup::Find(sg);
50   OB_ASSERT(pSG != nullptr);
51 
52   // Check also for errors and warnings
53   string summary = obErrorLog.GetMessageSummary();
54 //  OB_ASSERT( summary.find("error") == string::npos);
55 //  OB_ASSERT( summary.find("warning") == string::npos);
56 
57   OB_ASSERT( pSG->GetId() == 64 );
58 }
59 
testSpaceGroupClean()60 void testSpaceGroupClean()
61 {
62   // See https://github.com/openbabel/openbabel/pull/254
63   OBConversion conv;
64   OBMol mol;
65   conv.SetInFormat("cif");
66   conv.SetOutFormat("pdb");
67   conv.ReadFile(&mol, GetFilename("test02.cif"));
68   OBUnitCell* pUC = (OBUnitCell*)mol.GetData(OBGenericDataType::UnitCell);
69   const SpaceGroup* pSG = pUC->GetSpaceGroup();
70   SpaceGroup* sg = new SpaceGroup(*pSG);
71   pSG = SpaceGroup::Find(sg);
72   OB_ASSERT(pSG != nullptr);
73 
74   // Check also for errors and warnings
75   string summary = obErrorLog.GetMessageSummary();
76 //  OB_ASSERT( summary.find("error") == string::npos);
77 //  OB_ASSERT( summary.find("warning") == string::npos);
78 
79   OB_ASSERT( pSG->GetId() == 166 );
80 
81   string pdb = conv.WriteString(&mol);
82   pdb = conv.WriteString(&mol);
83 
84   OB_ASSERT(pdb.find("H -3 m") != string::npos);
85 }
86 
testSpaceGroupTransformations()87 void testSpaceGroupTransformations()
88 {
89   // See https://github.com/openbabel/openbabel/pull/254
90   SpaceGroup group;
91   vector<string> trans;
92   vector<string> trans_exp;
93   vector<string> trans_got;
94 
95   // Same transformation
96   trans_exp.push_back("x,y,z");
97   trans.push_back("x,y,z");
98   trans.push_back(" x , y , z ");
99   trans.push_back("x,y+1,z");
100   trans.push_back("x,y-1,z-1");
101   trans.push_back("x,y-1,z");
102   // Same transformation
103   trans_exp.push_back("x,-y,z");
104   trans.push_back("x,-y,z");
105   trans.push_back("x,1-y,z");
106   trans.push_back("x,-y+1,z");
107   // Same transformation
108   trans_exp.push_back("x,-y,-z");
109   trans.push_back("x,-y,-z");
110   trans.push_back("x,1-y,1-z");
111   trans.push_back("x,-y+1,-z+1");
112   // Same transformation
113   trans_exp.push_back("x,-y,-y-z");
114   trans.push_back("x,-y,-z-y");
115   trans.push_back("x,1-y,-y+1-z");
116   trans.push_back("x,-y+1,-y-z+1");
117   // Same transformation
118   trans_exp.push_back("x,-y,1/6-y-z");
119   trans.push_back("x,-y,-z-y+1/6");
120   trans.push_back("x,-y,-z-y+7/6");
121   trans.push_back("x,1-y,7/6-y+1-z");
122   trans.push_back("x,-y+1,-y-z+1+1/6");
123   trans.push_back("x,-y+1,-y+1/6-z+1");
124   // Same transformation
125   trans_exp.push_back("x,3/4-y+z,5/6-y-z");
126   trans.push_back("x,3/4-y+z,-1/6-z-y");
127   trans.push_back("x,-y+3/4+z,-z-y-1/6");
128   trans.push_back("x,z-y+3/4,-z-y-7/6");
129   trans.push_back("x,1+z+3/4-y,-7/6-y-z");
130   trans.push_back("X , 3 / 4 - Y + 1 + z , - Y - Z - 1 / 6 ");
131   trans.push_back("x,z-y+1+3/4,-y-1/6-z+1");
132 
133   vector<string>::const_iterator i, iend;
134   iend = trans.end();
135   for (i = trans.begin(); i != iend; ++i)
136     group.AddTransform(i->c_str());
137 
138   // Loop over symmetry operators
139   transform3dIterator ti;
140   const transform3d *t = group.BeginTransform(ti);
141   while(t){
142     trans_got.push_back(t->DescribeAsString());
143     //cout << t->DescribeAsString() << "\n";
144     t = group.NextTransform(ti);
145   }
146 
147   OB_ASSERT( trans_exp.size() == trans_got.size() );
148   OB_ASSERT( equal(trans_exp.begin(), trans_exp.end(), trans_got.begin()) );
149 }
150 
testDecayToP1()151 void testDecayToP1()
152 {
153   // See https://github.com/openbabel/openbabel/pull/261
154   OBConversion conv;
155   OBMol mol;
156   conv.SetInFormat("cif");
157   conv.ReadFile(&mol, GetFilename("test03.cif"));
158   OBUnitCell* pUC = (OBUnitCell*)mol.GetData(OBGenericDataType::UnitCell);
159   const SpaceGroup* pSG = pUC->GetSpaceGroup();
160   SpaceGroup* sg = new SpaceGroup(*pSG);
161   pSG = SpaceGroup::Find(sg);
162   OB_ASSERT(pSG != nullptr);
163 
164   // Check also for errors and warnings
165   string summary = obErrorLog.GetMessageSummary();
166   OB_ASSERT( summary.find("2 warnings") != string::npos);
167 
168   OB_ASSERT( pSG->GetId() == 1 );
169 }
170 
testAlternativeOrigin()171 void testAlternativeOrigin()
172 {
173   // See https://github.com/openbabel/openbabel/pull/1558
174   OBConversion conv;
175   OBMol mol;
176   conv.SetInFormat("cif");
177   conv.ReadFile(&mol, GetFilename("test04.cif"));
178   OBUnitCell* pUC = (OBUnitCell*)mol.GetData(OBGenericDataType::UnitCell);
179   const SpaceGroup* pSG = pUC->GetSpaceGroup();
180   SpaceGroup* sg = new SpaceGroup(*pSG);
181   pSG = SpaceGroup::Find(sg);
182 
183   string summary = obErrorLog.GetMessageSummary();
184   OB_ASSERT( summary.find("warning") == string::npos);
185   OB_ASSERT( pSG != nullptr );
186   OB_ASSERT( pSG->GetOriginAlternative() == 1);
187 }
188 
testPdbOutAlternativeOrigin()189 void testPdbOutAlternativeOrigin()
190 {
191   // See https://github.com/openbabel/openbabel/pull/1558
192   OBConversion conv;
193   OBMol mol;
194   conv.SetInFormat("cif");
195   conv.SetOutFormat("pdb");
196   conv.ReadFile(&mol, GetFilename("test04.cif"));
197 
198   string pdb = conv.WriteString(&mol);
199   // ending space is needed to check that there is no origin set
200   OB_ASSERT(pdb.find("P 4/n b m ") != string::npos);
201 
202   conv.AddOption("o", OBConversion::OUTOPTIONS);
203   pdb = conv.WriteString(&mol);
204 
205   OB_ASSERT(pdb.find("P 4/n b m:1") != string::npos);
206 }
207 
testPdbOutHexagonalAlternativeOrigin()208 void testPdbOutHexagonalAlternativeOrigin()
209 {
210   // See https://github.com/openbabel/openbabel/pull/1558
211   OBConversion conv;
212   OBMol mol;
213   conv.SetInFormat("cif");
214   conv.SetOutFormat("pdb");
215   conv.ReadFile(&mol, GetFilename("test02.cif"));
216 
217   string pdb = conv.WriteString(&mol);
218   conv.AddOption("o", OBConversion::OUTOPTIONS);
219   pdb = conv.WriteString(&mol);
220 
221   OB_ASSERT(pdb.find("H -3 m") != string::npos);
222 
223   // Test with missing Hall name in the CIF
224   // https://github.com/openbabel/openbabel/pull/1578
225   OBMol mol_nohall;
226   conv.ReadFile(&mol_nohall, GetFilename("test02.nohall.cif"));
227 
228   pdb = conv.WriteString(&mol_nohall);
229 
230   OB_ASSERT(pdb.find("H -3 m") != string::npos);
231 }
232 
testPdbOutAlternativeOriginSilicon()233 void testPdbOutAlternativeOriginSilicon()
234 {
235   // See https://github.com/openbabel/openbabel/pull/1558
236   OBConversion conv;
237   OBMol mol;
238   conv.SetInFormat("cif");
239   conv.SetOutFormat("pdb");
240   conv.ReadFile(&mol, GetFilename("test05.cif"));
241 
242   string pdb = conv.WriteString(&mol);
243   conv.AddOption("o", OBConversion::OUTOPTIONS);
244   pdb = conv.WriteString(&mol);
245 
246   OB_ASSERT(pdb.find("F d 3 m:1") != string::npos);
247 }
248 
testPdbOutHexagonalAlternativeOrigin2()249 void testPdbOutHexagonalAlternativeOrigin2()
250 {
251   // See https://github.com/openbabel/openbabel/pull/1558
252   OBConversion conv;
253   OBMol mol;
254   conv.SetInFormat("cif");
255   conv.SetOutFormat("pdb");
256   conv.ReadFile(&mol, GetFilename("test06.cif"));
257 
258   string pdb = conv.WriteString(&mol);
259   conv.AddOption("o", OBConversion::OUTOPTIONS);
260   pdb = conv.WriteString(&mol);
261 
262   OB_ASSERT(pdb.find("H -3 m") != string::npos);
263 }
264 
testPdbRemSpacesHMName()265 void testPdbRemSpacesHMName()
266 {
267   // See https://github.com/openbabel/openbabel/pull/1558
268   OBConversion conv;
269   OBMol mol;
270   conv.SetInFormat("cif");
271   conv.SetOutFormat("pdb");
272   conv.ReadFile(&mol, GetFilename("test07.cif"));
273 
274   string pdb = conv.WriteString(&mol);
275   conv.AddOption("o", OBConversion::OUTOPTIONS);
276   pdb = conv.WriteString(&mol);
277 
278   OB_ASSERT(pdb.find("I41/amd:2") != string::npos);
279 }
280 
testPdbOccupancies()281 void testPdbOccupancies()
282 {
283   // See https://github.com/openbabel/openbabel/pull/1558
284   OBConversion conv;
285   OBMol mol;
286   conv.SetInFormat("cif");
287   conv.SetOutFormat("pdb");
288   conv.ReadFile(&mol, GetFilename("test08.cif"));
289 
290   string pdb = conv.WriteString(&mol);
291   conv.AddOption("o", OBConversion::OUTOPTIONS);
292   pdb = conv.WriteString(&mol);
293 
294   OB_ASSERT(pdb.find("HETATM    1 NA   UNL     1       0.325   0.000   4.425  0.36") != string::npos);
295   OB_ASSERT(pdb.find("HETATM   17  O   UNL     8       1.954   8.956   3.035  1.00") != string::npos);
296 
297   OBMol mol_pdb;
298   conv.SetInFormat("pdb");
299   conv.ReadFile(&mol_pdb, GetFilename("test09.pdb"));
300 
301   pdb = conv.WriteString(&mol_pdb);
302   OB_ASSERT(pdb.find("HETATM    1 NA   UNL     1       0.325   0.000   4.425  0.36") != string::npos);
303   OB_ASSERT(pdb.find("HETATM    2 NA   UNL     1       0.002   8.956   1.393  0.10") != string::npos);
304   OB_ASSERT(pdb.find("HETATM   17  O   UNL     8       1.954   8.956   3.035  1.00") != string::npos);
305 }
306 
testCIFMolecules()307 void testCIFMolecules()
308 {
309   // See https://github.com/openbabel/openbabel/pull/1558
310   OBConversion conv;
311   OBMol mol;
312   conv.SetInFormat("cif");
313   conv.SetOutFormat("smi"); // check for disconnected fragments
314   conv.ReadFile(&mol, GetFilename("1519159.cif"));
315 
316   string smi = conv.WriteString(&mol);
317   // never, never disconnected fragments from a molecule
318   OB_ASSERT(smi.find(".") == string::npos);
319 }
320 
testCIFOutputFormat()321 void testCIFOutputFormat()
322 {
323   // See https://github.com/openbabel/openbabel/pull/2170
324   OBConversion conv;
325   OBMol mol;
326   conv.SetInFormat("sdf");
327   conv.SetOutFormat("cif"); // check correct format
328   conv.ReadFile(&mol, GetFilename("kevlar.sdf"));
329 
330   string cif = conv.WriteString(&mol);
331 
332   string ref = "    H0       H      -71.99400 -128.76240   56.30360    1.000";
333   OB_ASSERT(cif.find(ref) != string::npos);
334 }
335 
cifspacegrouptest(int argc,char * argv[])336 int cifspacegrouptest(int argc, char* argv[])
337 {
338   int defaultchoice = 1;
339 
340   int choice = defaultchoice;
341 
342   if (argc > 1) {
343     if(sscanf(argv[1], "%d", &choice) != 1) {
344       printf("Couldn't parse that input as a number\n");
345       return -1;
346     }
347   }
348 
349   // Define location of file formats for testing
350   #ifdef FORMATDIR
351     char env[BUFF_SIZE];
352     snprintf(env, BUFF_SIZE, "BABEL_LIBDIR=%s", FORMATDIR);
353     putenv(env);
354   #endif
355 
356   switch(choice) {
357   case 1:
358     testSpaceGroupUniqueTransformations();
359     break;
360   case 2:
361     testSpaceGroupClean();
362     break;
363   case 3:
364     testSpaceGroupTransformations();
365     break;
366   case 4:
367     testDecayToP1();
368     break;
369   case 5:
370     testAlternativeOrigin();
371     break;
372   case 6:
373     testPdbOutAlternativeOrigin();
374     break;
375   case 7:
376     testPdbOutHexagonalAlternativeOrigin();
377     break;
378   case 8:
379     testPdbOutAlternativeOriginSilicon();
380     break;
381   case 9:
382     testPdbOutHexagonalAlternativeOrigin2();
383     break;
384   case 10:
385     testPdbRemSpacesHMName();
386   break;
387   case 11:
388     testPdbOccupancies();
389   break;
390   case 12:
391     testCIFMolecules();
392   break;
393   case 13:
394     testCIFOutputFormat();
395   break;
396   default:
397     cout << "Test number " << choice << " does not exist!\n";
398     return -1;
399   }
400 
401   return(0);
402 }
403