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