1 /**********************************************************************
2 obrotate = rotate a tortional bond matched by a SMART pattern
3 Copyright (C) 2003 Fabien Fontaine
4 Some portions Copyright (C) 2004-2005 Geoffrey R. Hutchison
5 Some portions Copyright (C) 2008 Tim Vandermeersch
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 /*
21 Require a SMART pattern, a file containing molecule coordinates
22 4 atoms of the SMART pattern to define the tortional, an angle value
23 The angle value must be in degree
24 the 2 atoms of the rotating bond must be bonded but the 2 others not
25 the part of the molecule on the side of the second atom is kept fixed
26 whereas the part on the side of the third atom is rotated.
27 example of command line:
28 obrotate "[nH]ccccc[O,C][C,O]" test.sdf 1 6 7 8 180.0
29 */
30
31
32 // used to set import/export for Cygwin DLLs
33 #ifdef WIN32
34 #define USING_OBDLL
35 #endif
36
37 #include <openbabel/babelconfig.h>
38 #include <openbabel/mol.h>
39 #include <openbabel/atom.h>
40 #include <openbabel/parsmart.h>
41 #include <openbabel/rotamer.h>
42 //#include <unistd.h>
43 #include <openbabel/obconversion.h>
44 #include <cstdlib>
45 using namespace std;
46 using namespace OpenBabel;
47
48 ///////////////////////////////////////////////////////////////////////////////
49 //! \brief Set a tortional bond to a given angle
main(int argc,char ** argv)50 int main(int argc,char **argv)
51 {
52 OBAtom *a1, *a2, *a3, *a4;
53 unsigned int smartor[4]= {0,0,0,0};// atoms of the tortional in the SMART
54 float angle = 0; // tortional angle value to set in degree
55 char *FileIn = nullptr, *Pattern = nullptr;
56 unsigned int i, t, errflg = 0;
57 int c;
58 string err;
59 bool changeAll = false; // default to only change the last matching torsion
60
61 // parse the command line -- optional -a flag to change all matching torsions
62 if (argc < 8 || argc > 9) {
63 errflg++;
64 } else {
65 // Fetch the option and shift values after the option
66 if (argc == 9) {
67 int curArg = 0;
68 while (curArg < 9) {
69 if (strcmp(argv[curArg], "-a") == 0) {
70 changeAll = true;
71 break;
72 }
73 ++curArg;
74 }
75 // We expect -a and so changeAll should be true
76 if (!changeAll)
77 errflg++;
78
79 // now let's shift values
80 while (curArg < 8) {
81 argv[curArg] = argv[curArg+1];
82 }
83 }
84 FileIn = argv[2];
85 Pattern = argv[1];
86 // Read the atom position
87 for(i=3, t=0; i<7; ++i, ++t) {
88 c = sscanf(argv[i], "%u", &smartor[t]);
89 if (c != 1) {
90 errflg++; // error in arguments, quit and warn user
91 break;
92 }
93 }
94 c = sscanf(argv[7], "%f", &angle);
95 if (c != 1) {
96 errflg++; // error in arguments, quit and warn user
97 }
98 if (argc == 9) {
99 if (strcmp(argv[8], "-a") == 0)
100 changeAll = true;
101 else
102 errflg++; // error in arguments, quit and warn user
103 }
104 }
105
106 if (errflg) {
107 cerr << "Usage: obrotate \"PATTERN\" <filename> <atom1> <atom2> <atom3> <atom4> <angle> [-a]" << endl;
108 exit(-1);
109 }
110
111 // create pattern
112 OBSmartsPattern sp;
113 sp.Init(Pattern);
114 if (sp.NumAtoms() < 4) {
115 cerr << "obrotate: The number of atoms in the SMART pattern must be higher than 3." << endl;
116 exit(-1);
117 }
118
119 for (i=0; i<4; ++i) {
120 if ( smartor[i] < 1 || smartor[i] > sp.NumAtoms()) {
121 cerr << "obrotate: The torsional atom values must be between 1 and "
122 << sp.NumAtoms()
123 << ", which is the number of atoms in the SMART pattern." << endl;
124 exit(-1);
125 }
126 }
127
128 OBConversion conv; //NF...
129 OBFormat* format = conv.FormatFromExt(FileIn);
130 if(!(format && conv.SetInAndOutFormats(format, format))) { //in and out formats same
131 cerr << "obrotate: cannot read and/or write this file format!" << endl;
132 exit (-1);
133 } //...NF
134
135 //Open the molecule file
136 ifstream ifs;
137
138 // Read the file
139 ifs.open(FileIn);
140 if (!ifs) {
141 cerr << "obrotate: cannot read input file!" << endl;
142 exit (-1);
143 }
144
145 OBMol mol;
146 vector< vector <int> > maplist; // list of matched atoms
147 vector< vector <int> >::iterator m; // and its iterators
148 // int tindex;
149
150 // Set the angles
151 for (;;) {
152 mol.Clear();
153 //NF ifs >> mol; // Read molecule
154 conv.Read(&mol,&ifs); //NF
155 if (mol.Empty())
156 break;
157
158 if (sp.Match(mol)) {
159 // if match perform rotation
160 maplist = sp.GetUMapList(); // get unique matches
161
162 if (maplist.size() > 1)
163 cerr << "obrotate: Found " << maplist.size() << " matches. Only last one will be rotated." << endl;
164
165 // look at all the mapping atom but save only the last one.
166 for (m = maplist.begin(); m != maplist.end(); ++m) {
167 a1 = mol.GetAtom( (*m)[ smartor[0] - 1] );
168 a2 = mol.GetAtom( (*m)[ smartor[1] - 1] );
169 a3 = mol.GetAtom( (*m)[ smartor[2] - 1] );
170 a4 = mol.GetAtom( (*m)[ smartor[3] - 1] );
171 if (changeAll)
172 mol.SetTorsion(a1, a2, a3, a4, angle * DEG_TO_RAD);
173 }
174
175 if ( !a2->IsConnected(a3) ) {
176 cerr << "obrotate: The atoms of the rotating bond must be bonded." << endl;
177 exit(-1);
178 }
179
180 if (!changeAll)
181 mol.SetTorsion(a1, a2, a3, a4, angle * DEG_TO_RAD);
182 } else {
183 cerr << "obrotate: Found 0 matches for the SMARTS pattern." << endl;
184 exit(-1);
185 }
186 //NF cout << mol;
187 conv.Write(&mol,&cout); //NF
188 }
189
190 return(0);
191 }
192
193
194 /* obrotate man page*/
195 /** \page obrotate batch-rotate dihedral angles matching SMARTS patterns
196 *
197 * \n
198 * \par SYNOPSIS
199 *
200 * \b obrotate '<SMARTS-pattern>' \<filename\> \<atom1\> \<atom2\> \<atom3\> \<atom4\> \<angle\>
201 *
202 * \par DESCRIPTION
203 *
204 * The obrotate program rotates the torsional (dihedral) angle of a specified
205 * bond in molecules to that defined by the user. In other words, it does the
206 * same as a user setting an angle in a molecular modelling package, but much
207 * faster and in batch mode.
208 * \n\n
209 * The four atom IDs required are indexes into the SMARTS pattern, which starts
210 * at atom 1. The angle supplied is in degrees. The two atoms used to set
211 * the dihedral angle \<atom1\> and \<atom4\> do not need to be connected
212 * to the atoms of the bond \<atom2\> and \<atom3\> in any way.
213 *\n\n
214 * The order of the atoms matters -- the portion of the molecule attached to
215 * \<atom1\> and \<atom2\> remain fixed, but the portion bonded to \<atom3\> and
216 & \<atom4\> moves.
217 *
218 * \par EXAMPLES
219 * - Let's say that you want to define the conformation of a large number of
220 * molecules with a pyridyl scaffold and substituted with an aliphatic chain
221 * at the 3-position, for example for docking or 3D-QSAR purposes.
222 * \n\n
223 * To set the value of the first dihedral angle to 90 degrees:\n
224 * obrotate "c1ccncc1CCC" pyridines.sdf 5 6 7 8 90
225 * \n
226 * Here 6 and 7 define the bond to rotate in the SMARTS patter, i.e., c1-C and
227 * atoms 5 and 8 define the particular dihedral angle to rotate.
228 * - Since the atoms to define the dihedral do not need to be directly
229 * connected, the nitrogen in the pyridine can be used:\n
230 * obrotate "c1ccncc1CCC" pyridines.sdf 4 6 7 8 90
231 *
232 * - Keep the pyridyl ring fixed and moves the aliphatic chain:\n
233 * obrotate "c1ccncc1CCC" pyridines.sdf 5 6 7 8 90
234 * - Keep the aliphatic chain fixed and move the pyridyl ring:\n
235 * obrotate "c1ccncc1CCC" pyridines.sdf 8 7 6 5 90
236 *
237 * \par AUTHORS
238 *
239 * The obrotate program was contributed by \b Fabien \b Fontaine.
240 *
241 * Open Babel is currently maintained by \b Geoff \b Hutchison, \b Chris \b Morley and \b Michael \b Banck.
242 *
243 * For more contributors to Open Babel, see http://openbabel.org/THANKS.shtml
244 *
245 * \par COPYRIGHT
246 * Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
247 * Some portions Copyright (C) 2001-2005 by Geoffrey R. Hutchison \n \n
248 * This program is free software; you can redistribute it and/or modify
249 * it under the terms of the GNU General Public License as published by
250 * the Free Software Foundation version 2 of the License.\n \n
251 * This program is distributed in the hope that it will be useful,
252 * but WITHOUT ANY WARRANTY; without even the implied warranty of
253 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
254 * GNU General Public License for more details.
255 *
256 * \par SEE ALSO
257 * The web pages for Open Babel can be found at: http://openbabel.org/ \n
258 * A guide for constructing SMARTS patterns can be found at: http://www.daylight.com/dayhtml/doc/theory/theory.smarts.html
259 **/
260