~ubuntu-branches/ubuntu/vivid/openbabel/vivid-proposed

« back to all changes in this revision

Viewing changes to src/smi.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michael Banck
  • Date: 2002-02-01 01:19:44 UTC
  • Revision ID: james.westby@ubuntu.com-20020201011944-4a9guzcsnpezzawx
Tags: upstream-1.99
ImportĀ upstreamĀ versionĀ 1.99

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**********************************************************************
 
2
Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
 
3
 
 
4
This program is free software; you can redistribute it and/or modify
 
5
it under the terms of the GNU General Public License as published by
 
6
the Free Software Foundation version 2 of the License.
 
7
 
 
8
This program is distributed in the hope that it will be useful,
 
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
GNU General Public License for more details.
 
12
***********************************************************************/
 
13
 
 
14
#include "mol.h"
 
15
#include "typer.h"
 
16
#include "smi.h"
 
17
 
 
18
//#define KEKULE
 
19
 
 
20
namespace OpenBabel {
 
21
 
 
22
bool WriteSmiles(ostream &ofs,OBMol &mol,char *title)
 
23
{
 
24
  char buffer[BUFF_SIZE],tmp[BUFF_SIZE];
 
25
 
 
26
  OBMol2Smi m2s;
 
27
 
 
28
  m2s.Init();
 
29
  m2s.CorrectAromaticAmineCharge(mol);
 
30
  m2s.CreateSmiString(mol,buffer);
 
31
 
 
32
  strcpy(tmp,(title) ? title:mol.GetTitle());
 
33
  ofs << buffer << ' ' << tmp << endl;
 
34
  return(true);
 
35
}
 
36
 
 
37
void OBMol2Smi::CreateSmiString(OBMol &mol,char *buffer)
 
38
{
 
39
  OBAtom *atom;
 
40
  OBSmiNode *root;
 
41
  buffer[0] = '\0';
 
42
  vector<OBNodeBase*>::iterator i;
 
43
 
 
44
  for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
 
45
//    if ((!atom->IsHydrogen() || atom->GetValence() == 0) && !_uatoms[atom->GetIdx()])
 
46
    if (!atom->IsHydrogen() && !_uatoms[atom->GetIdx()])
 
47
      if (!atom->IsChiral()) //don't use chiral atoms as root node
 
48
        {
 
49
          //clear out closures in case structure is dot disconnected
 
50
          _vclose.clear();
 
51
          _atmorder.clear();
 
52
          _storder.clear();
 
53
          _vopen.clear();
 
54
          //dot disconnected structure
 
55
          if (strlen(buffer) > 0) strcat(buffer,"."); 
 
56
          root = new OBSmiNode (atom);
 
57
          BuildTree(root);
 
58
          FindClosureBonds(mol);
 
59
          if (mol.Has2D()) AssignCisTrans(root);
 
60
          ToSmilesString(root,buffer);
 
61
          delete root;
 
62
        }
 
63
}
 
64
 
 
65
bool OBMol2Smi::BuildTree(OBSmiNode *node)
 
66
{
 
67
  vector<OBEdgeBase*>::iterator i;
 
68
  OBAtom *nbr,*atom = node->GetAtom();
 
69
  
 
70
  _uatoms.SetBitOn(atom->GetIdx()); //mark the atom as visited
 
71
  _atmorder.push_back(atom->GetIdx()); //store the atom ordering
 
72
  _storder.push_back(atom->GetIdx()); //store the atom ordering for stereo
 
73
 
 
74
  for (nbr = atom->BeginNbrAtom(i);nbr;nbr = atom->NextNbrAtom(i))
 
75
    if (!nbr->IsHydrogen() && !_uatoms[nbr->GetIdx()])
 
76
      {
 
77
                        _ubonds.SetBitOn((*i)->GetIdx());
 
78
                        OBSmiNode *next = new OBSmiNode (nbr);
 
79
                        next->SetParent(atom);
 
80
                        node->SetNextNode(next,(OBBond*)*i);
 
81
                        BuildTree(next);
 
82
        }
 
83
 
 
84
  return(true);
 
85
}
 
86
 
 
87
void OBMol2Smi::ToSmilesString(OBSmiNode *node,char *buffer)
 
88
{
 
89
  char tmpbuf[10];
 
90
  OBAtom *atom = node->GetAtom();
 
91
 
 
92
  //write the current atom to the string
 
93
  GetSmilesElement(node,tmpbuf);
 
94
  strcat(buffer,tmpbuf);
 
95
 
 
96
    //handle ring closures here
 
97
  vector<pair<int,OBBond*> > vc = GetClosureDigits(atom);
 
98
  if (!vc.empty())
 
99
    {
 
100
      vector<pair<int,OBBond*> >::iterator i;
 
101
      for (i = vc.begin();i != vc.end();i++)
 
102
        {
 
103
          if (i->second)
 
104
            {
 
105
              if (i->second->IsUp())                              strcat(buffer,"\\");
 
106
              if (i->second->IsDown())                            strcat(buffer,"/");
 
107
#ifndef KEKULE
 
108
              if (i->second->GetBO() == 2 && !i->second->IsAromatic()) strcat(buffer,"=");
 
109
#else
 
110
              if (i->second->GetBO() == 2)                        strcat(buffer,"=");
 
111
#endif
 
112
              if (i->second->GetBO() == 3)                        strcat(buffer,"#");
 
113
            }
 
114
              
 
115
          if (i->first > 9) strcat(buffer,"%");
 
116
          sprintf(tmpbuf,"%d",i->first); 
 
117
          strcat(buffer,tmpbuf);
 
118
        }
 
119
    }
 
120
 
 
121
  //follow path to child atoms
 
122
  OBBond *bond;
 
123
  for (int i = 0;i < node->Size();i++)
 
124
    {
 
125
      bond = node->GetNextBond(i);
 
126
      if (i+1 < node->Size())                        strcat(buffer,"(");
 
127
      if (bond->IsUp())                              strcat(buffer,"\\");
 
128
      if (bond->IsDown())                            strcat(buffer,"/");
 
129
#ifndef KEKULE
 
130
      if (bond->GetBO() == 2 && !bond->IsAromatic()) strcat(buffer,"=");
 
131
#else
 
132
      if (bond->GetBO() == 2)                        strcat(buffer,"=");
 
133
#endif
 
134
      if (bond->GetBO() == 3)                        strcat(buffer,"#");
 
135
 
 
136
      ToSmilesString(node->GetNextNode(i),buffer);
 
137
      if (i+1 < node->Size()) strcat(buffer,")");
 
138
    }
 
139
}
 
140
 
 
141
void OBMol2Smi::GetClosureAtoms(OBAtom *atom,vector<OBNodeBase*> &va)
 
142
{
 
143
 
 
144
//look through closure list for start atom
 
145
  vector<OBEdgeBase*>::iterator i;
 
146
  for (i = _vclose.begin();i != _vclose.end();i++)
 
147
          if (*i)
 
148
  {
 
149
          if (((OBBond*)*i)->GetBeginAtom() == atom)
 
150
            va.push_back(((OBBond*)*i)->GetEndAtom());
 
151
          if (((OBBond*)*i)->GetEndAtom() == atom)
 
152
            va.push_back(((OBBond*)*i)->GetBeginAtom());
 
153
  }
 
154
 
 
155
  OBAtom *nbr;
 
156
  vector<pair<OBAtom*,pair<int,int> > >::iterator j;
 
157
  for (j = _vopen.begin();j != _vopen.end();j++)
 
158
          for (nbr = atom->BeginNbrAtom(i);nbr;nbr = atom->NextNbrAtom(i))
 
159
                  if (nbr == j->first)
 
160
                        va.push_back(nbr);  
 
161
}
 
162
 
 
163
vector<pair<int,OBBond*> > OBMol2Smi::GetClosureDigits(OBAtom *atom)
 
164
{
 
165
  vector<pair<int,OBBond*> > vc; vc.clear();
 
166
 
 
167
  //look through closure list for start atom
 
168
  int idx,bo;
 
169
  OBBond *bond;
 
170
  vector<OBEdgeBase*>::iterator i;
 
171
  for (i = _vclose.begin();i != _vclose.end();i++)
 
172
    if ((bond=(OBBond*)*i))
 
173
      if (bond->GetBeginAtom() == atom || bond->GetEndAtom() == atom)
 
174
        {
 
175
          idx = GetUnusedIndex();
 
176
          vc.push_back(pair<int,OBBond*> (idx,bond));
 
177
          bo = (bond->IsAromatic())? 1 : bond->GetBO();
 
178
          _vopen.push_back(pair<OBAtom*,pair<int,int> >
 
179
                           (bond->GetNbrAtom(atom),pair<int,int>(idx,bo)));
 
180
          *i = NULL;//remove bond from closure list
 
181
        }
 
182
 
 
183
  //try to complete closures
 
184
  if (!_vopen.empty())
 
185
    {
 
186
      vector<pair<OBAtom*,pair<int,int> > >::iterator j;
 
187
      for (j = _vopen.begin();j != _vopen.end();)
 
188
        if (j->first == atom)
 
189
          {
 
190
            vc.push_back(pair<int,OBBond*> (j->second.first,(OBBond*)NULL));
 
191
            _vopen.erase(j);
 
192
            j = _vopen.begin();
 
193
          }
 
194
        else j++;
 
195
    }
 
196
 
 
197
  return(vc);
 
198
}
 
199
 
 
200
void OBMol2Smi::FindClosureBonds(OBMol &mol)
 
201
{
 
202
  //find closure bonds
 
203
  OBAtom *a1,*a2;
 
204
  OBBond *bond;
 
205
  vector<OBEdgeBase*>::iterator i;
 
206
  OBBitVec bv;
 
207
  bv.FromVecInt(_storder);
 
208
 
 
209
  for (bond = mol.BeginBond(i);bond;bond = mol.NextBond(i))
 
210
    if (!_ubonds[bond->GetIdx()] && bv[bond->GetBeginAtomIdx()])
 
211
      {
 
212
        a1 = bond->GetBeginAtom();
 
213
        a2 = bond->GetEndAtom();
 
214
        if (!a1->IsHydrogen() && !a2->IsHydrogen()) 
 
215
          _vclose.push_back(bond);
 
216
      }
 
217
 
 
218
  vector<OBEdgeBase*>::reverse_iterator j;
 
219
  vector<int>::iterator k;
 
220
 
 
221
  //modify _order to reflect ring closures
 
222
  for (j = _vclose.rbegin();j != _vclose.rend();j++)
 
223
    {
 
224
      bond = (OBBond*)*j;
 
225
      a1 = a2 = NULL;
 
226
 
 
227
      for (k = _storder.begin();k != _storder.end();k++)
 
228
        if (bond->GetBeginAtomIdx() == *k || 
 
229
            bond->GetEndAtomIdx() == *k)
 
230
          if (!a1) a1 = mol.GetAtom(*k);
 
231
          else if (!a2) 
 
232
            {
 
233
              a2 = mol.GetAtom(*k);
 
234
              _storder.erase(k);
 
235
              break;
 
236
            }
 
237
 
 
238
      for (k = _storder.begin();k != _storder.end();k++)
 
239
                if (a1->GetIdx() == *k)
 
240
                {
 
241
                        k++;
 
242
                        if (k != _storder.end()) _storder.insert(k,a2->GetIdx());
 
243
                        else                     _storder.push_back(a2->GetIdx());
 
244
                        break;
 
245
                }
 
246
    }
 
247
}
 
248
 
 
249
int OBMol2Smi::GetUnusedIndex()
 
250
{
 
251
  int idx=1;
 
252
 
 
253
  vector<pair<OBAtom*,pair<int,int> > >::iterator j;
 
254
  for (j = _vopen.begin();j != _vopen.end();)
 
255
    if (j->second.first == idx)
 
256
      {
 
257
        idx++; //increment idx and start over if digit is already used
 
258
        j = _vopen.begin();
 
259
      }
 
260
    else j++;
 
261
 
 
262
  return(idx);
 
263
}
 
264
 
 
265
void OBMol2Smi::CorrectAromaticAmineCharge(OBMol &mol)
 
266
{
 
267
  OBAtom *atom;
 
268
  vector<OBNodeBase*>::iterator i;
 
269
 
 
270
  _aromNH.clear();
 
271
  _aromNH.resize(mol.NumAtoms()+1);
 
272
 
 
273
  for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
 
274
    if (atom->IsNitrogen() && atom->IsAromatic())
 
275
      if (atom->GetHvyValence() == 2)
 
276
        {
 
277
          if (atom->GetValence() == 3 || atom->GetImplicitValence() == 3)
 
278
            _aromNH[atom->GetIdx()] = true;
 
279
        }
 
280
}
 
281
 
 
282
void OBMol2Smi::AssignCisTrans(OBSmiNode *node)
 
283
{
 
284
  //traverse the tree searching for acyclic olefins - if it
 
285
  //has at least one heavy atom attachment on each end assign stereochem
 
286
 
 
287
  OBBond *bond;
 
288
  for (int i = 0;i < node->Size();i++)
 
289
    {
 
290
      bond = node->GetNextBond(i);
 
291
      if (bond->GetBO() == 2 && !bond->IsInRing())
 
292
        {
 
293
          OBAtom *b = node->GetAtom();
 
294
          OBAtom *c = bond->GetNbrAtom(b);
 
295
 
 
296
        //skip allenes
 
297
          if (b->GetHyb() == 1 || c->GetHyb() == 1) continue;
 
298
 
 
299
          if (b->GetHvyValence() > 1 && c->GetHvyValence() > 1)
 
300
            {
 
301
              OBAtom *a,*d;
 
302
              vector<OBEdgeBase*>::iterator j,k;
 
303
 
 
304
              //look for bond with assigned stereo as in poly-ene
 
305
              for (a = b->BeginNbrAtom(j);a;a = b->NextNbrAtom(j))
 
306
                if (((OBBond*)*j)->IsUp() ||((OBBond*)*j)->IsDown())
 
307
                  break;
 
308
 
 
309
              if (!a)
 
310
              for (a = b->BeginNbrAtom(j);a;a = b->NextNbrAtom(j))
 
311
                if (a != c && !a->IsHydrogen())
 
312
                  break;
 
313
              for (d = c->BeginNbrAtom(k);d;d = c->NextNbrAtom(k))
 
314
                if (d != b && !d->IsHydrogen())
 
315
                  break;
 
316
              obAssert(a); obAssert(d);
 
317
              
 
318
              if (((OBBond*)*j)->IsUp() || ((OBBond*)*j)->IsDown()) //stereo already assigned
 
319
                {
 
320
                  if (fabs(CalcTorsionAngle(a->GetVector(),b->GetVector(),
 
321
                                       c->GetVector(),d->GetVector())) > 10.0)
 
322
                    if (((OBBond*)*j)->IsUp()) ((OBBond*)*k)->SetUp();
 
323
                    else              ((OBBond*)*k)->SetDown();
 
324
                  else
 
325
                    if (((OBBond*)*j)->IsUp()) ((OBBond*)*k)->SetDown();
 
326
                    else              ((OBBond*)*k)->SetUp();
 
327
                }
 
328
              else //assign stereo to both ends
 
329
                {
 
330
                  ((OBBond*)*j)->SetUp();
 
331
                  if (fabs(CalcTorsionAngle(a->GetVector(),b->GetVector(),
 
332
                                       c->GetVector(),d->GetVector())) > 10.0)
 
333
                    ((OBBond*)*k)->SetUp();
 
334
                  else
 
335
                    ((OBBond*)*k)->SetDown();
 
336
                }
 
337
            }
 
338
        }
 
339
      AssignCisTrans(node->GetNextNode(i));
 
340
    }
 
341
}
 
342
 
 
343
void OBMol2Smi::Init()
 
344
  {
 
345
  _vclose.clear();
 
346
  _atmorder.clear();
 
347
  _storder.clear();
 
348
  _aromNH.clear(); 
 
349
  _uatoms.Clear();
 
350
  _ubonds.Clear();
 
351
  _vopen.clear();
 
352
}
 
353
 
 
354
bool OBMol2Smi::GetSmilesElement(OBSmiNode *node,char *element)
 
355
{
 
356
  //***handle reference atom stuff here and return***
 
357
  char symbol[10];
 
358
  bool bracketElement = false;
 
359
  bool normalValence = true;
 
360
 
 
361
  OBAtom *atom = node->GetAtom();
 
362
 
 
363
  int bosum = atom->KBOSum();
 
364
 
 
365
  switch (atom->GetAtomicNum())
 
366
    {
 
367
    case 0: break;
 
368
    case 5: /*bracketElement = !(normalValence = (bosum == 3)); break;*/ break;
 
369
    case 6: break;
 
370
    case 7: 
 
371
                                if (atom->IsAromatic() && atom->GetHvyValence() == 2 && atom->GetImplicitValence() == 3)
 
372
                                {
 
373
                                        bracketElement = !(normalValence = false); break;
 
374
                                }
 
375
                                else
 
376
                                        bracketElement = !(normalValence = (bosum == 3 || bosum == 5)); break;
 
377
    case 8: break;
 
378
    case 9: break;
 
379
    case 15: break;
 
380
    case 16: 
 
381
                        bracketElement = !(normalValence = (bosum == 2 || bosum == 4 || bosum == 6)); break;
 
382
    case 17: break;
 
383
    case 35: break;
 
384
    case 53: break;
 
385
    
 
386
    default:
 
387
      bracketElement = true;
 
388
    }
 
389
 
 
390
  if (atom->GetHvyValence() > 2 && atom->IsChiral())
 
391
    if (((OBMol*)atom->GetParent())->HasNonZeroCoords() || atom->HasChiralitySpecified())
 
392
      bracketElement = true;
 
393
 
 
394
  if (atom->GetFormalCharge() != 0) //bracket charged elements
 
395
    bracketElement = true;
 
396
 
 
397
  if (!bracketElement)
 
398
    {
 
399
      if (!atom->GetAtomicNum())
 
400
        {
 
401
          bool external = false;
 
402
          vector<pair<int,pair<OBAtom *,OBBond *> > > *externalBonds = 
 
403
                        (vector<pair<int,pair<OBAtom *,OBBond *> > > *)((OBMol*)atom->GetParent())->GetData("extBonds");
 
404
          vector<pair<int,pair<OBAtom *,OBBond *> > >::iterator externalBond;
 
405
 
 
406
          if (externalBonds)
 
407
            for(externalBond = externalBonds->begin();externalBond != externalBonds->end();externalBond++)
 
408
              {
 
409
                if (externalBond->second.first == atom)
 
410
                  {
 
411
                    external = true;
 
412
                    strcpy(symbol,"&");
 
413
                    OBBond *bond = externalBond->second.second;
 
414
                    if (bond->IsUp())                              strcat(symbol,"\\");
 
415
                    if (bond->IsDown())                            strcat(symbol,"/");
 
416
#ifndef KEKULE
 
417
                    if (bond->GetBO() == 2 && !bond->IsAromatic()) strcat(symbol,"=");
 
418
                    if (bond->GetBO() == 2 && bond->IsAromatic())  strcat(symbol,";");
 
419
#else
 
420
                    if (bond->GetBO() == 2)                        strcat(symbol,"=");
 
421
#endif
 
422
                    if (bond->GetBO() == 3)                        strcat(symbol,"#");
 
423
                    sprintf(symbol,"%s%d",symbol,externalBond->first);
 
424
                    break;
 
425
                  }
 
426
              }
 
427
 
 
428
          if(!external) strcpy(symbol,"*");
 
429
        }
 
430
      else
 
431
        {
 
432
          strcpy(symbol,etab.GetSymbol(atom->GetAtomicNum()));
 
433
#ifndef KEKULE
 
434
          if (atom->IsAromatic()) symbol[0] = tolower(symbol[0]);
 
435
#endif
 
436
        }
 
437
      strcpy(element,symbol);
 
438
 
 
439
      return(true);
 
440
    }
 
441
 
 
442
  strcpy(element,"[");
 
443
  if (!atom->GetAtomicNum()) strcpy(symbol,"*");
 
444
  else
 
445
    {
 
446
      strcpy(symbol,etab.GetSymbol(atom->GetAtomicNum()));
 
447
#ifndef KEKULE
 
448
      if (atom->IsAromatic()) symbol[0] = tolower(symbol[0]);
 
449
#endif
 
450
    }
 
451
  strcat(element,symbol);
 
452
  
 
453
          //if (atom->IsCarbon() && atom->GetHvyValence() > 2 && atom->IsChiral())
 
454
  if (atom->GetHvyValence() > 2 && atom->IsChiral())
 
455
    {
 
456
      char stereo[5];
 
457
      if (GetChiralStereo(node,stereo))
 
458
                  strcat(element,stereo);
 
459
    }
 
460
 
 
461
  //add extra hydrogens
 
462
//  if (!normalValence && atom->ImplicitHydrogenCount())
 
463
  if (atom->ImplicitHydrogenCount())
 
464
    {
 
465
      strcat(element,"H");
 
466
      if (atom->ImplicitHydrogenCount() > 1)
 
467
        {
 
468
          char tcount[10];
 
469
          sprintf(tcount,"%d",atom->ImplicitHydrogenCount());
 
470
          strcat(element,tcount);
 
471
        }
 
472
    }
 
473
 
 
474
  //cat charge on the end
 
475
  if (atom->GetFormalCharge() != 0)
 
476
    {
 
477
 
 
478
/*
 
479
                if (atom->ImplicitHydrogenCount())
 
480
                {
 
481
                        cerr << "imp = " << atom->GetAtomicNum() << ' ' << atom->GetImplicitValence() << endl;
 
482
      strcat(element,"H");
 
483
      if (atom->ImplicitHydrogenCount() > 1)
 
484
                        {
 
485
                                char tcount[10];
 
486
                                sprintf(tcount,"%d",atom->ImplicitHydrogenCount());
 
487
                                strcat(element,tcount);
 
488
                        }
 
489
                }
 
490
        */      
 
491
                        if (atom->GetFormalCharge() > 0) strcat(element,"+");
 
492
                        else                             strcat(element,"-");
 
493
 
 
494
      if (abs(atom->GetFormalCharge()) > 1)
 
495
                        {
 
496
                                char tcharge[10];
 
497
                                sprintf(tcharge,"%d",abs(atom->GetFormalCharge()));
 
498
                                strcat(element,tcharge);
 
499
                        }
 
500
    }
 
501
 
 
502
  strcat(element,"]");
 
503
 
 
504
  return(true);
 
505
}
 
506
 
 
507
bool OBMol2Smi::GetChiralStereo(OBSmiNode *node,char *stereo)
 
508
{
 
509
  bool is2D=false;
 
510
  float torsion;
 
511
  OBAtom *a,*b,*c,*d,hydrogen;
 
512
 
 
513
  b = node->GetAtom();
 
514
  OBMol *mol = (OBMol*)b->GetParent();
 
515
 
 
516
  if (!mol->HasNonZeroCoords()) //must have come in from smiles string
 
517
    {
 
518
      if (!b->HasChiralitySpecified()) return(false);
 
519
      if (b->IsClockwise())          strcpy(stereo,"@@");
 
520
      else if (b->IsAntiClockwise()) strcpy(stereo,"@");
 
521
      else return(false);
 
522
      //if (b->GetHvyValence() == 3) strcat(stereo,"H");
 
523
      return(true);
 
524
    }
 
525
 
 
526
  //give peudo Z coords if mol is 2D
 
527
  if (!mol->Has3D())
 
528
    {
 
529
      Vector v,vz(0.0,0.0,1.0);
 
530
      is2D = true;
 
531
          OBAtom *nbr;
 
532
      OBBond *bond;
 
533
      vector<OBEdgeBase*>::iterator i;
 
534
      for (bond = b->BeginBond(i);bond;bond = b->NextBond(i))
 
535
          {
 
536
                  nbr = bond->GetEndAtom();
 
537
                  if (nbr != b)
 
538
                  {
 
539
                          v = nbr->GetVector();
 
540
                          if (bond->IsWedge()) v += vz;
 
541
                          else
 
542
                                  if (bond->IsHash()) v -= vz;
 
543
 
 
544
                          nbr->SetVector(v);
 
545
                  }
 
546
                  else
 
547
                  {
 
548
                          nbr = bond->GetBeginAtom();
 
549
                          v = nbr->GetVector();
 
550
                          if (bond->IsWedge()) v -= vz;
 
551
                          else
 
552
                                  if (bond->IsHash()) v += vz;
 
553
 
 
554
                          nbr->SetVector(v);
 
555
                  }
 
556
        }
 
557
    }
 
558
 
 
559
  c = d = NULL;
 
560
  a = node->GetParent();
 
561
  obAssert(a); //chiral atom can't be used as root node - must have parent
 
562
      
 
563
  if (b->GetHvyValence() == 3) //must have attached hydrogen
 
564
    {
 
565
      if (b->GetValence() == 4)//has explicit hydrogen
 
566
        {
 
567
          vector<OBEdgeBase*>::iterator i;
 
568
          for (c = b->BeginNbrAtom(i);c;c = b->NextNbrAtom(i))
 
569
            if (c->IsHydrogen())
 
570
              break;
 
571
          obAssert(c);
 
572
        }
 
573
      else  //implicit hydrogen
 
574
        {
 
575
          Vector v;
 
576
          b->GetNewBondVector(v,1.0);
 
577
          hydrogen.SetVector(v);
 
578
          c = &hydrogen;
 
579
        }
 
580
    }
 
581
 
 
582
  //get connected atoms in order
 
583
  OBAtom *nbr;
 
584
  vector<int>::iterator j;
 
585
 
 
586
  //try to get neighbors that are closure atoms in the order they appear in the string
 
587
  vector<OBNodeBase*> va;
 
588
  GetClosureAtoms(b,va);
 
589
  if (!va.empty())
 
590
  {
 
591
          vector<OBNodeBase*>::iterator k;
 
592
          for (k = va.begin();k != va.end();k++)
 
593
                  if (*k != a)
 
594
                  {
 
595
                        if (!c) c = (OBAtom*)*k;
 
596
                        else if (!d) d = (OBAtom*)*k;
 
597
                  }
 
598
  }
 
599
 
 
600
  for (j = _storder.begin();j != _storder.end();j++)
 
601
    {
 
602
      nbr = mol->GetAtom(*j);
 
603
      if (!b->IsConnected(nbr)) continue;
 
604
      if (nbr == a || nbr == b || nbr == c) continue;
 
605
      if (!c)      c = nbr;
 
606
      else if (!d) d = nbr;
 
607
    }
 
608
 
 
609
  torsion = CalcTorsionAngle(a->GetVector(),b->GetVector(), 
 
610
                             c->GetVector(),d->GetVector());
 
611
 
 
612
  strcpy(stereo,(torsion<0.0)?"@":"@@");
 
613
  //if (b->GetHvyValence() == 3) strcat(stereo,"H");
 
614
 
 
615
  //re-zero psuedo-coords
 
616
  if (is2D)
 
617
    {
 
618
      Vector v;
 
619
      OBAtom *atom;
 
620
      vector<OBNodeBase*>::iterator k;
 
621
      for (atom = mol->BeginAtom(k);atom;atom = mol->NextAtom(k))
 
622
          {
 
623
                  v = atom->GetVector();
 
624
                  v.SetZ(0.0);
 
625
                  atom->SetVector(v);
 
626
          }
 
627
    }
 
628
 
 
629
  return(true);
 
630
}
 
631
 
 
632
bool WriteFixFile(ostream &ofs,OBMol &mol)
 
633
{
 
634
  char buffer[BUFF_SIZE];
 
635
  OBMol2Smi m2s;
 
636
 
 
637
  m2s.Init();
 
638
  //m2s.AssignCisTrans(mol);
 
639
  m2s.CorrectAromaticAmineCharge(mol);
 
640
  m2s.CreateSmiString(mol,buffer);
 
641
 
 
642
  OBAtom *atom;
 
643
  vector<int>::iterator i;
 
644
  vector<int> order = m2s.GetOutputOrder();
 
645
  ofs << buffer << endl;
 
646
  
 
647
  int j;
 
648
  for (j = 0;j < mol.NumConformers();j++)
 
649
    {
 
650
      mol.SetConformer(j);
 
651
      for (i = order.begin();i != order.end();i++)
 
652
        {
 
653
          atom = mol.GetAtom(*i);
 
654
          sprintf(buffer,"%9.3f %9.3f %9.3f",atom->GetX(),atom->GetY(),atom->GetZ());
 
655
          ofs << buffer<< endl;
 
656
        }
 
657
    }
 
658
  return(true);
 
659
}
 
660
 
 
661
OBSmiNode::OBSmiNode(OBAtom *atom) 
 
662
{
 
663
  _atom = atom;
 
664
  _parent = NULL;
 
665
  _nextnode.clear();
 
666
  _nextbond.clear();
 
667
}
 
668
 
 
669
void OBSmiNode::SetNextNode(OBSmiNode *node,OBBond *bond) 
 
670
{
 
671
  _nextnode.push_back(node);
 
672
  _nextbond.push_back(bond);
 
673
}
 
674
 
 
675
OBSmiNode::~OBSmiNode()
 
676
{
 
677
  vector<OBSmiNode*>::iterator i;
 
678
  for (i = _nextnode.begin();i != _nextnode.end();i++)
 
679
    delete (*i);
 
680
}
 
681
 
 
682
 
 
683
bool WriteTheSmiles(OBMol & mol,char *out)
 
684
{
 
685
  char buffer[2*BUFF_SIZE];
 
686
 
 
687
  OBMol2Smi m2s;
 
688
 
 
689
  m2s.Init();
 
690
  m2s.CorrectAromaticAmineCharge(mol);
 
691
  m2s.CreateSmiString(mol,buffer);
 
692
 
 
693
  strcpy(out,buffer);
 
694
  return(true);
 
695
 
 
696
}
 
697
 
 
698
}