Exemple #1
0
  OBMolPairIter::OBMolPairIter(OBMol &mol)
  {
    _parent = &mol;

    bool foundPair = false;
    OBAtom *a = _parent->BeginAtom(_i);
    if (!a) 
      return;
    OBAtom *b = _parent->BeginAtom(_j);
    while (!foundPair) {
      b = _parent->NextAtom(_j);

      if (!b) {
        a = _parent->NextAtom(_i);
	if (!a)
          return;
        b = _parent->BeginAtom(_j);
      }

      if (a->GetIdx() >= b->GetIdx()) continue;
      if (a->IsConnected(b)) continue;
      if (a->IsOneThree(b)) continue;

      foundPair = true;
    }

    _pair.clear();
    _pair.push_back(a->GetIdx());
    _pair.push_back(b->GetIdx());
  }
Exemple #2
0
  OBMolAtomDFSIter& OBMolAtomDFSIter::operator++()
  {
    if (!_stack.empty())
      {
        _ptr = _stack.top();
        _stack.pop();
      }
    else // are there any disconnected subgraphs?
      {
        int next = _notVisited.FirstBit();
        if (next != _notVisited.EndBit())
          {
            _ptr = _parent->GetAtom(next + 1);
            _notVisited.SetBitOff(next);
          }
        else
          _ptr = NULL;
      }

    if (_ptr)
      {
        vector<OBBond*>::iterator i;
        OBAtom *a;
        
        for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i))
          if (_notVisited[a->GetIdx() - 1])
            {
              _stack.push(a);
              _notVisited.SetBitOff(a->GetIdx() - 1);
            }
      }

    return *this;
  }
Exemple #3
0
  // Seems to make a vector chirality become filled with array of +/- 1 for chiral atoms.
  void GetChirality(OBMol &mol, std::vector<int> &chirality)
  {
    chirality.resize(mol.NumAtoms()+1);
    fill(chirality.begin(),chirality.end(),0);

    OBAtom *atom;
    vector<OBAtom*>::iterator i;
    for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
      if (atom->IsChiral())
        {
          if (!atom->HasChiralVolume())
            {
              double sv = CalcSignedVolume(mol,atom);
              if (sv < 0.0)
                {
                  chirality[atom->GetIdx()-1] = -1;
                  atom->SetNegativeStereo();
                }
              else if (sv > 0.0)
                {
                  chirality[atom->GetIdx()-1] = 1;
                  atom->SetPositiveStereo();
                }
            }
          else // already calculated signed volume (e.g., imported from somewhere)
            {
              if (atom ->IsPositiveStereo())
                chirality[atom->GetIdx()-1] = 1;
              else
                chirality[atom->GetIdx()-1] = -1;
            }
        }
  }
Exemple #4
0
bool WriteGromos96(ostream &ofs,OBMol &mol,double fac)
{ 
  char type_name[10];
  char res_name[10],padded_name[10];
  char buffer[BUFF_SIZE];
  int res_num;

  sprintf(buffer,"#GENERATED BY OPEN BABEL %s",BABEL_VERSION);
  ofs << buffer << endl;

  /* GROMOS wants a TITLE block, so let's write one*/
  sprintf(buffer,"TITLE\n%s\nEND",mol.GetTitle());
  ofs << buffer << endl;
  ofs << "POSITION" << endl;

  OBAtom *atom;
  OBResidue *res;
  vector<OBNodeBase*>::iterator i;

  for(atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
    {
      if (res = atom->GetResidue())
	{
	  strcpy(res_name,(char*)res->GetName().c_str());
	  strcpy(type_name,(char*)res->GetAtomID(atom).c_str());
	  res_num = res->GetNum();
	}
      else
	{
	  strcpy(type_name,etab.GetSymbol(atom->GetAtomicNum()));
	  strcpy(res_name,"UNK");
	  sprintf(padded_name,"%2s",type_name);
	  strcpy(type_name,padded_name);
	  res_num = 1;
	}
      
      sprintf(buffer,"%5d %5s %5s %6d %15.5f %15.5f %15.5f",
	      res_num,res_name,type_name,atom->GetIdx(),
	      atom->x()*fac,atom->y()*fac,atom->z()*fac);
      ofs << buffer << endl;

      if (!(atom->GetIdx()%10))
      {
	sprintf(buffer,"# %d",atom->GetIdx());
	ofs << buffer << endl;
      }
    }

  ofs << "END" << endl;

  return(true);
}
Exemple #5
0
  bool OBDepict::AddAtomLabels(AtomLabelType type)
  {
    d->painter->SetPenColor(OBColor("red"));
    d->painter->SetFillColor(OBColor("red"));
    d->painter->SetFontSize((int)(GetFontSize() * 0.8));// smaller text
    OBAtomIterator i;
    for (OBAtom *atom = d->mol->BeginAtom(i); atom; atom = d->mol->NextAtom(i)) {
      vector3 pos(atom->GetVector());
      std::stringstream ss;
      switch (type) {
        case AtomId:
          ss << atom->GetId();
          d->painter->DrawText(pos.x(), pos.y(), ss.str());
          break;
        case AtomSymmetryClass:
          ss << GetAtomSymClass(atom);
          d->painter->DrawText(pos.x(), pos.y(), ss.str());
          break;
        case AtomIndex:
          ss << atom->GetIdx();
          d->painter->DrawText(pos.x(), pos.y(), ss.str());
          break;

        default:
          break;
      }
    }

    return true;    
  }
Exemple #6
0
void fingerprint2::getFragments(vector<int> levels, vector<int> curfrag,
					int level, OBAtom* patom, OBBond* pbond)
{
	//Recursive routine to analyse schemical structure and populate fragset and ringset
	//Hydrogens,charges(except dative bonds), spinMultiplicity ignored
	const int Max_Fragment_Size = 7;
	int bo=0;
	if(pbond)
	{
		bo = pbond->IsAromatic() ? 5 : pbond->GetBO();

//		OBAtom* pprevat = pbond->GetNbrAtom(patom);
//		if(patom->GetFormalCharge() && (patom->GetFormalCharge() == -pprevat->GetFormalCharge()))
//			++bo; //coordinate (dative) bond eg C[N+]([O-])=O is seen as CN(=O)=O
	}
	curfrag.push_back(bo);
	curfrag.push_back(patom->GetAtomicNum());
	levels[patom->GetIdx()-1] = level;

	vector<OBEdgeBase*>::iterator itr;
	OBBond *pnewbond;
//	PrintFpt(curfrag,(int)patom);
	for (pnewbond = patom->BeginBond(itr);pnewbond;pnewbond = patom->NextBond(itr))
	{
		if(pnewbond==pbond) continue; //don't retrace steps
		OBAtom* pnxtat = pnewbond->GetNbrAtom(patom);
		if(pnxtat->GetAtomicNum() == OBElements::Hydrogen) continue;

		int atlevel = levels[pnxtat->GetIdx()-1];
		if(atlevel) //ring
		{
			if(atlevel==1)
			{
				//If complete ring (last bond is back to starting atom) add bond at front
				//and save in ringset
				curfrag[0] = pnewbond->IsAromatic() ? 5 : pnewbond->GetBO();
				ringset.insert(curfrag);
 				curfrag[0] = 0;
			}
		}
		else //no ring
		{
			if(level<Max_Fragment_Size)
			{
//				TRACE("level=%d size=%d %p frag[0]=%p\n",level, curfrag.size(),&curfrag, &(curfrag[0]));
				//Do the next atom; levels, curfrag are passed by value and hence copied
				getFragments(levels, curfrag, level+1, pnxtat, pnewbond);
			}
		}
	}

	//do not save C,N,O single atom fragments
	if(curfrag[0]==0 &&
		(level>1 || patom->GetAtomicNum()>8  || patom->GetAtomicNum()<6))
	{
		fragset.insert(curfrag); //curfrag ignored if an identical fragment already present
//		PrintFpt(curfrag,level);
	}
}
Exemple #7
0
  bool BallStickFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
  {

    OBMol* pmol = pOb->CastAndClear<OBMol>();
    if(pmol==NULL)
      return false;

    //Define some references so we can use the old parameter names
    istream &ifs = *pConv->GetInStream();
    OBMol &mol = *pmol;
    const char* title = pConv->GetTitle();

    int i,natoms;
    char buffer[BUFF_SIZE];

    if (!ifs.getline(buffer,BUFF_SIZE))
      return(false);
    if (!ifs.getline(buffer,BUFF_SIZE))
      return(false);
    sscanf(buffer,"%d",&natoms);
    mol.ReserveAtoms(natoms);
    mol.BeginModify();

    double x,y,z;
    OBAtom *atom;
    vector<string> vs;
    vector<string>::iterator j;

    for (i = 1; i <= natoms;i ++)
      {
        if (!ifs.getline(buffer,BUFF_SIZE))
          return(false);
        tokenize(vs,buffer);
        if (vs.size() < 4)
          return(false);
        if (vs[0].size() > 1)
          vs[0][1] = tolower(vs[0][1]);
        atom = mol.NewAtom();
        x = atof((char*)vs[1].c_str());
        y = atof((char*)vs[2].c_str());
        z = atof((char*)vs[3].c_str());
        atom->SetVector(x,y,z); //set coordinates
        atom->SetAtomicNum(etab.GetAtomicNum(vs[0].c_str()));

        for (j = vs.begin()+4;j != vs.end();j++)
          mol.AddBond(atom->GetIdx(),atoi((char*)j->c_str()),1);
      }
    
    // clean out any remaining blank lines
    while(ifs.peek() != EOF && ifs.good() && 
          (ifs.peek() == '\n' || ifs.peek() == '\r'))
      ifs.getline(buffer,BUFF_SIZE);

    mol.EndModify();
    mol.SetTitle(title);
    return(true);
  }
Exemple #8
0
  void OBAromaticTyper::PropagatePotentialAromatic(OBAtom *atom)
  {
    int count = 0;
    OBAtom *nbr;
    vector<OBBond*>::iterator i;

    for (nbr = atom->BeginNbrAtom(i);nbr;nbr = atom->NextNbrAtom(i))
      if ((*i)->IsInRing() && _vpa[nbr->GetIdx()])
        count++;

    if (count < 2)
      {
        _vpa[atom->GetIdx()] = false;
        if (count == 1)
          for (nbr = atom->BeginNbrAtom(i);nbr;nbr = atom->NextNbrAtom(i))
            if ((*i)->IsInRing() && _vpa[nbr->GetIdx()])
              PropagatePotentialAromatic(nbr);
      }
  }
Exemple #9
0
void GenerateRingReference()
{
  std::ifstream ifs;
  if (!SafeOpen(ifs,"attype.00.smi")) return;

  std::ofstream ofs;
  if (!SafeOpen(ofs,"ringresults.txt")) return;

  int count;
  OBAtom *atom;
  OBBond *bond;
  char buffer[BUFF_SIZE];
  vector<OBRing*> vr;
  vector<OBEdgeBase*>::iterator i;
  vector<OBNodeBase*>::iterator j;
  vector<OBRing*>::iterator k;
  OBMol mol(SMI,SMI);
  OBFileFormat ff;

  for (;ifs;)
    {
      mol.Clear();
      ff.ReadMolecule(ifs, mol);
      if (mol.Empty()) continue;
      
      //write out ring bonds
      for (bond = mol.BeginBond(i);bond;bond = mol.NextBond(i))
	if (bond->IsInRing())
	  {
	    sprintf(buffer,"%3d",bond->GetIdx());
	    ofs << buffer;
	  }
      ofs << endl;

      vr = mol.GetSSSR();
      //write the total number of rings
      ofs << vr.size() << endl;

      //write the number of rings that each atom is a member of
      for (atom = mol.BeginAtom(j);atom;atom = mol.NextAtom(j))
	{
	  count = 0;
	  for (k = vr.begin();k != vr.end();k++)
	    if ((*k)->_pathset[atom->GetIdx()])
	      count++;

	  sprintf(buffer,"%3d",count);
	  ofs << buffer;
	}
      ofs << endl;

    }

  ThrowError("Ring perception test results written successfully");
}
Exemple #10
0
  OBMolAtomBFSIter::OBMolAtomBFSIter(OBMol &mol, int StartIndex):
    _parent(&mol), _ptr(_parent->GetAtom(StartIndex))
  {
    _notVisited.Resize(_parent->NumAtoms());
    _notVisited.Negate(); // all on
    _notVisited.SetBitOff(_ptr->GetIdx() - 1);

    // Set up storage for the depths
    _depth.resize(_parent->NumAtoms() + 1, 0);
    _depth[_ptr->GetIdx()] = 1;

    vector<OBBond*>::iterator i;
    OBAtom *a;

    for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i))
      {
        _queue.push(a);
        _depth[a->GetIdx()] = 2;
        _notVisited.SetBitOff(a->GetIdx() - 1);
      }
  }
bool ChemDrawXMLFormat::EndElement(const string& name)
{
    //unsigned int i;
    if(name=="n")
    {
        _pmol->AddAtom(_tempAtom);
        atoms[_tempAtom.GetIdx()] = _pmol->NumAtoms();
        _tempAtom.Clear();
    }
    else if(name=="b")
    {
        _pmol->AddBond(Begin, End, Order, Flag);
        Order = -1;
    }
    else if(name=="fragment") //this is the end of the molecule we are extracting
    {
        EnsureEndElement();
        _pmol->EndModify();

        // This alone will already store the "Formula" property in the molecule property block
        // The "Formula" is required for older ChemDraw generations allowing to match molecules to reaction properties
        string MolFormula=_pmol->GetFormula();

        // additional adding of "Formula" property is not required, as described above
        //OBPairData *dp = new OBPairData;
        //dp->SetAttribute("MolecularFormula");
        //dp->SetValue(MolFormula);
        //dp->SetOrigin(fileformatInput);
        //_pmol->SetData(dp);

        // alternative is using the molecular title, but a test is needed for preventing overwriting given titles, aka molecule ID
        //_pmol->SetTitle(MolFormula);

        atoms.clear();
        return false;//means stop parsing
    }
    /*
    // Forget that, the fragment, aka molecule, is in another XML hierachy tree than the data.
    // Parsing has already stopped before ever getting to this point
    else if(name=="tags")
    {
    }
    else if(name=="tableCell")
    {
      //OBPairData *dp = new OBPairData;
      //dp->SetAttribute(attr);
      //dp->SetValue(buff);
      //dp->SetOrigin(fileformatInput);
      //mol.SetData(dp);
    }*/

    return true;
}
Exemple #12
0
  void BuildOBRTreeVector(OBAtom *atom,OBRTree *prv,vector<OBRTree*> &vt,OBBitVec &bv)
  {
    vt[atom->GetIdx()] = new OBRTree (atom,prv);

    int i;
    OBAtom *nbr;
    OBMol *mol = (OBMol*)atom->GetParent();
    OBBitVec curr,used,next;
    vector<OBBond*>::iterator j;
    curr |= atom->GetIdx();
    used = bv|curr;

#define OB_RTREE_CUTOFF 20

    int level=0;
    for (;;)
      {
        next.Clear();
        for (i = curr.NextBit(0);i != bv.EndBit();i = curr.NextBit(i))
          {
            atom = mol->GetAtom(i);
            for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j))
              if (!used[nbr->GetIdx()])
                {
                  next |= nbr->GetIdx();
                  used |= nbr->GetIdx();
                  vt[nbr->GetIdx()] = new OBRTree (nbr,vt[atom->GetIdx()]);
                }
          }

        if (next.Empty())
          break;
        curr = next;
        level++;
        if (level > OB_RTREE_CUTOFF)
          break;
      }
#undef OB_RTREE_CUTOFF
  }
void ChemDrawXMLFormat::EnsureEndElement(void)
{
    if (_tempAtom.GetAtomicNum() != 0)
    {
        _pmol->AddAtom(_tempAtom);
        atoms[_tempAtom.GetIdx()] = _pmol->NumAtoms();
        _tempAtom.Clear();
    }
    else if (Order >= 0)
    {
        _pmol->AddBond(Begin, End, Order, Flag);
        Order = -1;
    }
}
Exemple #14
0
  OBMolAtomBFSIter& OBMolAtomBFSIter::operator++()
  {
    if (!_queue.empty())
      {
        _ptr = _queue.front();
        _queue.pop();
      }
    else // are there any disconnected subgraphs?
      {
        int next = _notVisited.FirstBit();
        if (next != _notVisited.EndBit())
          {
            _ptr = _parent->GetAtom(next + 1); // Atom index issue
            if (_ptr != NULL)
              _depth[_ptr->GetIdx()] = 1; // new island
            _notVisited.SetBitOff(next);
          }
        else
          _ptr = NULL;
      }

    if (_ptr)
      {
        vector<OBBond*>::iterator i;
        OBAtom *a;
        
        for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i))
          if (_notVisited[a->GetIdx() - 1])
            {
              _queue.push(a);
              _depth[a->GetIdx()] = _depth[_ptr->GetIdx()] + 1;
              _notVisited.SetBitOff(a->GetIdx() - 1);
            }
      }

    return *this;
  }
Exemple #15
0
  OBMolAtomDFSIter::OBMolAtomDFSIter(OBMol &mol, int StartIndex):
    _parent(&mol), _ptr(_parent->GetAtom(StartIndex))
  {
    _notVisited.Resize(_parent->NumAtoms());
    _notVisited.Negate(); // all on
    _notVisited.SetBitOff(_ptr->GetIdx() - 1);

    vector<OBBond*>::iterator i;
    OBAtom *a;

    for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i))
      {
        _stack.push(a);
        _notVisited.SetBitOff(a->GetIdx() - 1);
      }
  }
Exemple #16
0
  OBMolAtomDFSIter::OBMolAtomDFSIter(OBMol *mol, int StartIndex):
    _parent(mol), _ptr(_parent->GetAtom(StartIndex))
  {
    _notVisited.Resize(_parent->NumAtoms());
    _notVisited.SetRangeOn(0, _parent->NumAtoms() - 1);
    if (!_ptr) return;
    _notVisited.SetBitOff(_ptr->GetIdx() - 1);

    vector<OBBond*>::iterator i;
    OBAtom *a;

    for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i))
      {
        _stack.push(a);
        _notVisited.SetBitOff(a->GetIdx() - 1);
      }
  }
Exemple #17
0
  /** \brief Traverse a potentially aromatic cycle starting at @p root.
      \return  True if the cycle is likely aromatic
      \param root  The initial, "root" atom in traversing this ring
      \param atom  The current atom to visit and check
      \param prev  The bond traversed in moving to this @p atom
      \param er    The min and max number of pi electrons for this ring
      \param depth The maximum number of atoms to visit in a ring (e.g., 6)

      This method traverses a potentially aromatic ring, adding up the possible
      pi electrons for each atom. At the end (e.g., when @p atom == @p root)
      the Huekel 4n+2 rule is checked to see if there is a possible electronic
      configuration which corresponds to aromaticity.
  **/
  bool OBAromaticTyper::TraverseCycle(OBAtom *root, OBAtom *atom, OBBond *prev, 
                                      std::pair<int,int> &er,int depth)
  {
    if (atom == root)
      {
        int i;
        for (i = er.first;i <= er.second;++i)
          if (i%4 == 2 && i > 2)
            return(true);

        return(false);
      }

    if (!depth || !_vpa[atom->GetIdx()] || _visit[atom->GetIdx()])
      return(false);

    bool result = false;

    depth--;
    er.first  += _velec[atom->GetIdx()].first;
    er.second += _velec[atom->GetIdx()].second;

    _visit[atom->GetIdx()] = true;
    OBAtom *nbr;
    vector<OBBond*>::iterator i;
    for (nbr = atom->BeginNbrAtom(i);nbr;nbr = atom->NextNbrAtom(i))
      if (*i != prev && (*i)->IsInRing() && _vpa[nbr->GetIdx()])
        {
          if (TraverseCycle(root,nbr,(OBBond*)(*i),er,depth))
            {
              result = true;
              ((OBBond*) *i)->SetAromatic();
            }
        }

    _visit[atom->GetIdx()] = false;
    if (result)
      atom->SetAromatic();

    er.first  -= _velec[atom->GetIdx()].first;
    er.second -= _velec[atom->GetIdx()].second;

    return(result);
  }
Exemple #18
0
  void WriteChiral(ostream &ofs,OBMol &mol)
  {
    OBAtom *atom;
    vector<OBNodeBase*>::iterator i;
    char buffer[BUFF_SIZE];

    for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
      {
	if (atom->IsChiral())
	  {
	    sprintf(buffer,"%4s %5d is chiral: %s",
		    etab.GetSymbol(atom->GetAtomicNum()),
		    atom->GetIdx(),
		    (atom->IsClockwise() ? "clockwise" : "counterclockwise"));
	
	    ofs << buffer << endl;
	  }
      }
  }
Exemple #19
0
//copy data needed to write out pmol from obmol
void PMolCreator::copyFrom(OBMol& mol, bool deleteH)
{
	static OBIsotopeTable isotable;

	name = mol.GetTitle();
	//first construct atoms
	int typeindex[256]; //position in atoms vector of an atom type, indexed by atomic number
	int tmpatomindex[mol.NumAtoms()]; //position within the atom type vector
	memset(typeindex, -1, sizeof(typeindex));
	memset(tmpatomindex, -1, sizeof(tmpatomindex));


	for (OBAtomIterator aitr = mol.BeginAtoms(); aitr != mol.EndAtoms(); ++aitr)
	{
		OBAtom *atom = *aitr;
		unsigned int idx = atom->GetIdx();
		unsigned anum = atom->GetAtomicNum();
		assert(anum < 256);
		if(deleteH && anum == 1)
			continue;
		int pos = typeindex[anum];
		if (pos < 0) // no vector for this type yet
		{
			pos = typeindex[anum] = atoms.size();
			atoms.push_back(AtomGroup(anum));
		}

		tmpatomindex[idx] = atoms[pos].coords.size();
		atoms[pos].coords.push_back(FloatCoord(atom->x(), atom->y(), atom->z()));
	}
	//create mapping to actual atom index
	numAtoms = 0;
	BOOST_FOREACH(AtomGroup& ag, atoms)
	{	ag.startIndex = numAtoms;
		numAtoms += ag.coords.size();
	}
Exemple #20
0
 /* A recursive O(N) traversal of the molecule */
 static int FindRings(OBAtom *atom, int *avisit, unsigned char *bvisit,
                      unsigned int &frj, int depth)
 {
   OBBond *bond;
   int result = -1;
   vector<OBBond*>::iterator k;
   for(bond = atom->BeginBond(k);bond;bond=atom->NextBond(k)) {
     unsigned int bidx = bond->GetIdx();
     if (bvisit[bidx] == 0) {
       bvisit[bidx] = 1;
       OBAtom *nbor = bond->GetNbrAtom(atom);
       unsigned int nidx = nbor->GetIdx();
       int nvisit = avisit[nidx];
       if (nvisit == 0) {
         avisit[nidx] = depth+1;
         nvisit = FindRings(nbor,avisit,bvisit,frj,depth+1);
         if (nvisit > 0) {
           if (nvisit <= depth) {
             bond->SetInRing();
             if (result < 0 || nvisit < result)
               result = nvisit;
           }
         }
       } else {
         if (result < 0 || nvisit < result)
           result = nvisit;
         bond->SetClosure();
         bond->SetInRing();
         frj++;
       }
     }
   }
   if (result > 0 && result <= depth)
     atom->SetInRing();
   return result;
 }
Exemple #21
0
  void OBAromaticTyper::AssignAromaticFlags(OBMol &mol)
  {
    if (!_init)
      Init();

    if (mol.HasAromaticPerceived())
      return;
    mol.SetAromaticPerceived();
    obErrorLog.ThrowError(__FUNCTION__,
                          "Ran OpenBabel::AssignAromaticFlags", obAuditMsg);

    _vpa.clear();
    _vpa.resize(mol.NumAtoms()+1);
    _velec.clear();
    _velec.resize(mol.NumAtoms()+1);
    _root.clear();
    _root.resize(mol.NumAtoms()+1);

    OBBond *bond;
    OBAtom *atom;
    vector<OBAtom*>::iterator i;
    vector<OBBond*>::iterator j;

    //unset all aromatic flags
    for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
      atom->UnsetAromatic();
    for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j))
      bond->UnsetAromatic();

    int idx;
    vector<vector<int> >::iterator m;
    vector<OBSmartsPattern*>::iterator k;

    //mark atoms as potentially aromatic
    for (idx=0,k = _vsp.begin();k != _vsp.end();++k,++idx)
      if ((*k)->Match(mol))
        {
          _mlist = (*k)->GetMapList();
          for (m = _mlist.begin();m != _mlist.end();++m)
            {
              _vpa[(*m)[0]] = true;
              _velec[(*m)[0]] = _verange[idx];
            }
        }

    //sanity check - exclude all 4 substituted atoms and sp centers
    for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
      {
        if (atom->GetImplicitValence() > 3)
          {
            _vpa[atom->GetIdx()] = false;
            continue;
          }

        switch(atom->GetAtomicNum())
          {
            //phosphorus and sulfur may be initially typed as sp3
          case 6:
          case 7:
          case 8:
            if (atom->GetHyb() != 2)
              _vpa[atom->GetIdx()] = false;
            break;
          }
      }

    //propagate potentially aromatic atoms
    for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
      if (_vpa[atom->GetIdx()])
        PropagatePotentialAromatic(atom);

    //select root atoms
    SelectRootAtoms(mol);

    ExcludeSmallRing(mol); //remove 3 membered rings from consideration

    //loop over root atoms and look for aromatic rings
    _visit.clear();
    _visit.resize(mol.NumAtoms()+1);
    for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
      if (_root[atom->GetIdx()])
        CheckAromaticity(atom,14);

    //for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
    //	  if (atom->IsAromatic())
    //		  cerr << "aro = " <<atom->GetIdx()  << endl;

    //for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j))
    //if (bond->IsAromatic())
    //cerr << bond->GetIdx() << ' ' << bond->IsAromatic() << endl;
  }
  bool PDBFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
  {
    OBMol* pmol = dynamic_cast<OBMol*>(pOb);
    if(pmol==NULL)
      return false;

    //Define some references so we can use the old parameter names
    ostream &ofs = *pConv->GetOutStream();
    OBMol &mol = *pmol;

    unsigned int i;
    char buffer[BUFF_SIZE];
    char type_name[10], padded_name[10];
    char the_res[10];
    char the_chain = ' ';
    const char *element_name;
    int res_num;
    bool het=true;
    int model_num = 0;
    if (!pConv->IsLast() || pConv->GetOutputIndex() > 1)
      { // More than one molecule record
        model_num = pConv->GetOutputIndex(); // MODEL 1-based index
        snprintf(buffer, BUFF_SIZE, "MODEL %8d", model_num);
        ofs << buffer << endl;
      }

    if (strlen(mol.GetTitle()) > 0)
      snprintf(buffer, BUFF_SIZE, "COMPND    %s ",mol.GetTitle());
    else
      snprintf(buffer, BUFF_SIZE, "COMPND    UNNAMED");
    ofs << buffer << endl;

    snprintf(buffer, BUFF_SIZE, "AUTHOR    GENERATED BY OPEN BABEL %s",BABEL_VERSION);
    ofs << buffer << endl;

    // Write CRYST1 record, containing unit cell parameters, space group
    // and Z value (supposed to be 1)
    if (pmol->HasData(OBGenericDataType::UnitCell))
      {
        OBUnitCell *pUC = (OBUnitCell*)pmol->GetData(OBGenericDataType::UnitCell);
	
        snprintf(buffer, BUFF_SIZE,
                 "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s 1",
                 pUC->GetA(), pUC->GetB(), pUC->GetC(),
                 pUC->GetAlpha(), pUC->GetBeta(), pUC->GetGamma(),
                 pUC->GetSpaceGroup() ?
                 pUC->GetSpaceGroup()->GetHMName().c_str() : "P1");
        ofs << buffer << endl;
      }

    // before we write any records, we should check to see if any coord < -1000
    // which will cause errors in the formatting

    double minX, minY, minZ;
    minX = minY = minZ = -999.0f;
    FOR_ATOMS_OF_MOL(a, mol)
      {
        if (a->GetX() < minX)
          minX = a->GetX();
        if (a->GetY() < minY)
          minY = a->GetY();
        if (a->GetZ() < minZ)
          minZ = a->GetZ();
      }
    vector3 transV = VZero;
    if (minX < -999.0)
      transV.SetX(-1.0*minX - 900.0);
    if (minY < -999.0)
      transV.SetY(-1.0*minY - 900.0);
    if (minZ < -999.0)
      transV.SetZ(-1.0*minZ - 900.0);

    // if minX, minY, or minZ was never changed, shift will be 0.0f
    // otherwise, move enough so that smallest coord is > -999.0f
    mol.Translate(transV);

    OBAtom *atom;
    OBResidue *res;
    for (i = 1; i <= mol.NumAtoms(); i++)
      {
        atom = mol.GetAtom(i);
        strncpy(type_name, etab.GetSymbol(atom->GetAtomicNum()), sizeof(type_name));
        type_name[sizeof(type_name) - 1] = '\0';

        //two char. elements are on position 13 and 14 one char. start at 14
        if (strlen(type_name) > 1)
          type_name[1] = toupper(type_name[1]);
        else
          {
            char tmp[10];
            strncpy(tmp, type_name, 10);
            snprintf(type_name, sizeof(type_name), " %-3s", tmp);
          }

        if ( (res = atom->GetResidue()) != 0 )
          {
            het = res->IsHetAtom(atom);
            snprintf(the_res,4,"%s",(char*)res->GetName().c_str());
            snprintf(type_name,5,"%s",(char*)res->GetAtomID(atom).c_str());
            the_chain = res->GetChain();

            //two char. elements are on position 13 and 14 one char. start at 14
            if (strlen(etab.GetSymbol(atom->GetAtomicNum())) == 1)
              {
                if (strlen(type_name) < 4)
                  {
                    char tmp[16];
                    strncpy(tmp, type_name, 16);
                    snprintf(padded_name, sizeof(padded_name), " %-3s", tmp);
                    strncpy(type_name,padded_name,4);
                    type_name[4] = '\0';
                  }
                else
                  {
                    /*
                      type_name[4] = type_name[3];
                      type_name[3] = type_name[2];
                      type_name[2] = type_name[1];
                      type_name[1] = type_name[0];
                      type_name[0] = type_name[4];
                    */
                    type_name[4] = '\0';
                  }
              }
            res_num = res->GetNum();
          }
        else
          {
            strcpy(the_res,"UNK");
            snprintf(padded_name,sizeof(padded_name), "%s",type_name);
            strncpy(type_name,padded_name,4);
            type_name[4] = '\0';
            res_num = 1;
          }

        element_name = etab.GetSymbol(atom->GetAtomicNum());
        
        int charge = atom->GetFormalCharge();
        char scharge[3] = { ' ', ' ', '\0' };
        if(0 != charge)
          {
            snprintf(scharge, 3, "%+d", charge);
            char tmp = scharge[1];
            scharge[1] = scharge[0];
            scharge[0] = tmp;
          }
        snprintf(buffer, BUFF_SIZE, "%s%5d %-4s %-3s %c%4d    %8.3f%8.3f%8.3f  1.00  0.00          %2s%2s\n",
                 het?"HETATM":"ATOM  ",
                 i,
                 type_name,
                 the_res,
                 the_chain,
                 res_num,
                 atom->GetX(),
                 atom->GetY(),
                 atom->GetZ(),
                 element_name,
                 scharge);
        ofs << buffer;
      }

    OBAtom *nbr;
    vector<OBBond*>::iterator k;
    for (i = 1; i <= mol.NumAtoms(); i ++)
      {
        atom = mol.GetAtom(i);
        if (atom->GetValence() == 0)
          continue; // no need to write a CONECT record -- no bonds

        snprintf(buffer, BUFF_SIZE, "CONECT%5d", i);
        ofs << buffer;
        // Write out up to 4 real bonds per line PR#1711154
        unsigned int currentValence = 0;
        for (nbr = atom->BeginNbrAtom(k);nbr;nbr = atom->NextNbrAtom(k))
          {
            unsigned int order = mol.GetBond(atom, nbr)->GetBondOrder();
            unsigned int it_order = 0;
            for( it_order = 0; it_order < order; it_order++ )
              {
                if (0 != currentValence && 0 == currentValence % 4)
                  {
                    // Add the trailing space to finish this record
                    ofs << "                                       \n";
                    // write the start of a new CONECT record
                    snprintf(buffer, BUFF_SIZE, "CONECT%5d", i);
                    ofs << buffer;              
                  }
                currentValence++;
                snprintf(buffer, BUFF_SIZE, "%5d", nbr->GetIdx());
                ofs << buffer;
              }
          }

        // Add trailing spaces
        unsigned int remainingValence = currentValence % 4;
        if( 0 < remainingValence )
          {
            for (int count = 0; count < (4 - remainingValence); count++) 
              {
                snprintf(buffer, BUFF_SIZE, "     ");
                ofs << buffer;
              }
          }
        ofs << "                                                 \n";
      }

    snprintf(buffer, BUFF_SIZE, "MASTER        0    0    0    0    0    0    0    0 ");
    ofs << buffer;
    snprintf(buffer, BUFF_SIZE, "%4d    0 %4d    0\n",mol.NumAtoms(),mol.NumAtoms());
    ofs << buffer;

    ofs << "END\n";
    if (model_num) {
      ofs << "ENDMDL" << endl;
    }

    return(true);
  }
  bool MOL2Format::WriteMolecule(OBBase* pOb, OBConversion* pConv)
  {
    OBMol* pmol = dynamic_cast<OBMol*>(pOb);
    if(pmol==NULL)
      return false;

    //Define some references so we can use the old parameter names
    ostream &ofs = *pConv->GetOutStream();
    OBMol &mol = *pmol;
    bool ligandsOnly = pConv->IsOption("l", OBConversion::OUTOPTIONS)!=NULL;
 
    //The old code follows....
    string str,str1;
    char buffer[BUFF_SIZE],label[BUFF_SIZE];
    char rnum[BUFF_SIZE],rlabel[BUFF_SIZE];

    ofs << "@<TRIPOS>MOLECULE" << endl;
    str = mol.GetTitle();
    if (str.empty())
      ofs << "*****" << endl;
    else
      ofs << str << endl;

    snprintf(buffer, BUFF_SIZE," %d %d 0 0 0", mol.NumAtoms(),mol.NumBonds());
    ofs << buffer << endl;
    ofs << "SMALL" << endl;

    OBPairData *dp = (OBPairData*)mol.GetData("PartialCharges");
    if (dp != NULL) {
        // Tripos spec says:
        // NO_CHARGES, DEL_RE, GASTEIGER, GAST_HUCK, HUCKEL, PULLMAN, 
        // GAUSS80_CHARGES, AMPAC_CHARGES, MULLIKEN_CHARGES, DICT_ CHARGES,
        // MMFF94_CHARGES, USER_CHARGES
      if (dp->GetValue() == "Mulliken")
        ofs << "MULLIKEN_CHARGES" << endl;
      else // should pick from the Tripos types
        ofs << "GASTEIGER" << endl;
    }
    else { // No idea what these charges are... all our code sets "PartialCharges"
        ofs << "GASTEIGER" << endl;
    }

    ofs << "Energy = " << mol.GetEnergy() << endl;

    if (mol.HasData(OBGenericDataType::CommentData))
      {
        OBCommentData *cd = (OBCommentData*)mol.GetData(OBGenericDataType::CommentData);
        ofs << cd->GetData();
      }

    ofs << endl;
    ofs << "@<TRIPOS>ATOM" << endl;

    OBAtom *atom;
    OBResidue *res;

    vector<OBAtom*>::iterator i;
    vector<int> labelcount;
    labelcount.resize( etab.GetNumberOfElements() );

    ttab.SetFromType("INT");
    ttab.SetToType("SYB");

    for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
      {

        //
        //  Use sequentially numbered atom names if no residues
        //

        snprintf(label,BUFF_SIZE, "%s%d",
                 etab.GetSymbol(atom->GetAtomicNum()),
                 ++labelcount[atom->GetAtomicNum()]);
        strcpy(rlabel,"<1>");
        strcpy(rnum,"1");

        str = atom->GetType();
        ttab.Translate(str1,str);

        //
        //  Use original atom names if there are residues
        //

        if (!ligandsOnly && (res = atom->GetResidue()) )
          {
            // use original atom names defined by residue
            snprintf(label,BUFF_SIZE,"%s",(char*)res->GetAtomID(atom).c_str());
            // make sure that residue name includes its number
            snprintf(rlabel,BUFF_SIZE,"%s%d",res->GetName().c_str(), res->GetNum());
            snprintf(rnum,BUFF_SIZE,"%d",res->GetNum());
          }

        snprintf(buffer,BUFF_SIZE,"%7d%1s%-6s%12.4f%10.4f%10.4f%1s%-5s%4s%1s %-8s%10.4f",
                 atom->GetIdx(),"",label,
                 atom->GetX(),atom->GetY(),atom->GetZ(),
                 "",str1.c_str(),
                 rnum,"",rlabel,
                 atom->GetPartialCharge());
        ofs << buffer << endl;
      }

    ofs << "@<TRIPOS>BOND" << endl;
    OBBond *bond;
    vector<OBBond*>::iterator j;
    OBSmartsPattern pat;
    string s1, s2;
    for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j))
      {
        s1 = bond->GetBeginAtom()->GetType();
        s2 = bond->GetEndAtom()->GetType();
        if (bond->IsAromatic() || s1 == "O.co2" || s2 == "O.co2") 
          strcpy(label,"ar");
        else if (bond->IsAmide())
          strcpy(label,"am");
        else
          snprintf(label,BUFF_SIZE,"%d",bond->GetBO());

        snprintf(buffer, BUFF_SIZE,"%6d%6d%6d%3s%2s",
                 bond->GetIdx()+1,bond->GetBeginAtomIdx(),bond->GetEndAtomIdx(),
                 "",label);
        ofs << buffer << endl;
      }
    // NO trailing blank line (PR#1868929).
    //    ofs << endl;

    return(true);
  }
Exemple #24
0
void ring_test()
{
  ostringstream os;

#ifdef TESTDATADIR
  string testdatadir = TESTDATADIR;
  string results_file = testdatadir + "ringresults.txt";
  string smilestypes_file = testdatadir + "attype.00.smi";
#else
  string results_file = "files/ringresults.txt";
  string smilestypes_file = "files/attype.00.smi";
#endif

  cout << "# Testing ring perception..." << endl;

  std::ifstream mifs;
  os << "Bail out! Cannot read test data " << smilestypes_file.c_str();
  BOOST_REQUIRE_MESSAGE( SafeOpen(mifs, smilestypes_file.c_str()), os.str().c_str() );

  std::ifstream rifs;
  os.str("");
  os << "Bail out! Cannot read test data " << results_file.c_str();
  BOOST_REQUIRE_MESSAGE( SafeOpen(rifs, results_file.c_str()), os.str().c_str() );

  unsigned int size;
  OBBond *bond;
  OBAtom *atom;
  int count;
  char buffer[BUFF_SIZE];
  vector<string> vs;
  vector<OBRing*> vr;
  vector<bool> vb;
  vector<int> vi;
  OBMol mol;
  vector<string>::iterator i;
  vector<OBBond*>::iterator j;
  vector<OBAtom*>::iterator k;
  vector<OBRing*>::iterator m;
  OBConversion conv(&mifs, &cout);
  unsigned int currentTest = 0;

  BOOST_REQUIRE_MESSAGE( conv.SetInAndOutFormats("SMI","SMI"), "Bail out! SMILES format is not loaded" );

  for (;mifs;)
    {
      mol.Clear();
      conv.Read(&mol);
      if (mol.Empty())
        continue;
      
      BOOST_REQUIRE_MESSAGE( rifs.getline(buffer,BUFF_SIZE), "Bail out! error reading reference data" );

      vb.clear();
      vb.resize(mol.NumBonds(),false);
      //check ring bonds
      tokenize(vs,buffer);
      for (i = vs.begin();i != vs.end();i++)
        vb[atoi(i->c_str())] = true;

      for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j))
        {
          os.str("");
	  os << "ring bond data different than reference # Molecule: " << mol.GetTitle();
          BOOST_CHECK_MESSAGE( vb[bond->GetIdx()] == bond->IsInRing(), os.str().c_str() );
        }

      vr = mol.GetSSSR();
      BOOST_REQUIRE_MESSAGE( rifs.getline(buffer,BUFF_SIZE), "Bail out! error reading reference data" );
      sscanf(buffer,"%d",&size);

      os.str("");
      os << "SSSR size different than reference # Molecule: " << mol.GetTitle();
      BOOST_CHECK_MESSAGE( vr.size() == size, os.str().c_str() ); //check SSSR size

      BOOST_REQUIRE_MESSAGE( rifs.getline(buffer,BUFF_SIZE), "Bail out! error reading reference data" );

      tokenize(vs,buffer);
      i = vs.begin();
      for (atom = mol.BeginAtom(k);atom;atom = mol.NextAtom(k))
        {
          os.str("");
          os << "error in SSSR count # Molecule: " << mol.GetTitle();
          BOOST_CHECK_MESSAGE( i != vs.end(), os.str().c_str() ); //check SSSR size

          count = 0;
          for (m = vr.begin();m != vr.end();m++)
            if ((*m)->_pathset[atom->GetIdx()])
              count++;

	  os.str("");
          os << "ring membership test failed # Molecule: " << mol.GetTitle();
          BOOST_CHECK_MESSAGE( atoi(i->c_str()) == count, os.str().c_str() ); 

          i++;
        }
    }

}
Exemple #25
0
  bool ABINITFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
  {

    OBMol* pmol = pOb->CastAndClear<OBMol>();
    if(pmol==NULL)
      return false;

    //Define some references so we can use the old parameter names
    istream &ifs = *pConv->GetInStream();
    OBMol &mol = *pmol;
    const char* title = pConv->GetTitle();

    char buffer[BUFF_SIZE];
    string str;
    vector<string> vs;

    OBAtom *atom;
    int natom=-1;
    vector<int> atomicNumbers, atomTypes;
    double x, y, z;
    vector<vector3> atomPositions;
    vector<double> energies;

    // Translation vectors (if present)
    // aka rprim
    vector3 translationVectors[3];
    double acell[3]; // scale of lattice vectors
    int numTranslationVectors = 0;
    int symmetryCode = 0;

    mol.BeginModify();

    while (ifs.getline(buffer,BUFF_SIZE))
      {
        // tokens are listed in alphabetical order for code clarity
        if (strstr(buffer, "acell")) {
          tokenize(vs, buffer);
          if (vs.size() < 4)
            continue; // invalid line

          // acell=  7.6967369631E+00  7.6967369631E+00  7.6967369631E+00
          for (int i = 0; i < 3; ++i) {
            acell[i] = atof(vs[i+1].c_str());
          }
        }
        // Sometimes Cartesian has lower-case letter
        else if 
          ((strstr(buffer, "artesian coordinates")) &&
           (strstr(buffer, "(xcart)")) &&
           (natom > -1) //be sure natom has already been read
           )
          {
          double unit = BOHR_TO_ANGSTROM;
          if (strstr(buffer, "ngstrom"))
            unit = 1.0; // no conversion needed
          for (int i=0;i<natom;i++)
            {
              ifs.getline(buffer,BUFF_SIZE);
              tokenize(vs, buffer);
              if (vs.size() != 3) {
                obErrorLog.ThrowError
                  (__FUNCTION__,
                   "error while parsing coordinates of atoms", obWarning);
                return(false);
              }
              x = atof(vs[0].c_str()) * unit;
              y = atof(vs[1].c_str()) * unit;
              z = atof(vs[2].c_str()) * unit;
              atomPositions.push_back(vector3(x, y, z));
              // get next line
            }
          }
        else if (strstr(buffer, "natom")) {
          tokenize(vs, buffer);
          if (vs.size() != 2)
            continue;
          natom = atoi(vs[1].c_str());
        }
        else if (strstr(buffer, "rprim")) {
          numTranslationVectors = 0;
          int column;
          for (int i = 0; i < 3; ++i) {
            tokenize(vs, buffer);
            if (vs.size() < 3)
              break;

            // first line, rprim takes up a token
            if (i == 0)
              column = 1;
            else
              column = 0;

            x = atof((char*)vs[column].c_str()) * BOHR_TO_ANGSTROM;
            y = atof((char*)vs[column+1].c_str()) * BOHR_TO_ANGSTROM;
            z = atof((char*)vs[column+2].c_str()) * BOHR_TO_ANGSTROM;
            translationVectors[numTranslationVectors++].Set(x, y,z);
            ifs.getline(buffer,BUFF_SIZE);
          }
        }
        else if (strstr(buffer, "Symmetries")) {
          tokenize(vs, buffer, "()");
          // Should be something like (#160)
          symmetryCode = atoi(vs[1].substr(1).c_str());
        }
        else if (strstr(buffer, "typat")) {
          tokenize(vs, buffer);
          atomTypes.clear();
          for (unsigned int i = 1; i < vs.size(); ++i) {
            atomTypes.push_back(atoi(vs[i].c_str()));
          }
        }
        else if (strstr(buffer, "znucl")) {
          tokenize(vs, buffer);
          // make sure znucl is first token
          if (vs[0] != "znucl")
            continue;
          // push back the remaining tokens into atomicNumbers
          atomicNumbers.clear();
          atomicNumbers.push_back(0); // abinit starts typat with 1
          for (unsigned int i = 1; i < vs.size(); ++i)
            atomicNumbers.push_back(int(atof(vs[i].c_str())));
        }
        // xangst
        // forces
      }

    for (int i = 0; i < natom; ++i) {
      atom = mol.NewAtom();
      //set atomic number
      int idx = atom->GetIdx();
      int type = atomTypes[idx - 1];
      atom->SetAtomicNum(atomicNumbers[type]);
      // we set the coordinates by conformers in another loop
    }

    mol.EndModify();

    int numConformers = atomPositions.size() / natom;
    for (int i = 0; i < numConformers; ++i) {
      double *coordinates = new double[natom * 3];
      for (int j = 0; j < natom; ++j) {
        vector3 currentPosition = atomPositions[i*natom + j];
        coordinates[j*3] = currentPosition.x();
        coordinates[j*3 + 1] = currentPosition.y();
        coordinates[j*3 + 2] = currentPosition.z();
      }
      mol.AddConformer(coordinates);
    }
    // Delete first conformer, created by EndModify, bunch of 0s
    mol.DeleteConformer(0);
    // Set geometry to last one
    mol.SetConformer(mol.NumConformers() - 1);

    if (!pConv->IsOption("b",OBConversion::INOPTIONS))
      mol.ConnectTheDots();
    if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS))
      mol.PerceiveBondOrders();

    // Attach unit cell translation vectors if found
    if (numTranslationVectors > 0) {
      OBUnitCell* uc = new OBUnitCell;
      uc->SetData(acell[0] * translationVectors[0], acell[1] * translationVectors[1], acell[2] * translationVectors[2]);
      uc->SetOrigin(fileformatInput);
      if (symmetryCode)
        uc->SetSpaceGroup(symmetryCode);
      mol.SetData(uc);
    }

    mol.SetTitle(title);
    return(true);
  }
Exemple #26
0
  bool GROMOS96Format::WriteMolecule(OBBase* pOb, OBConversion* pConv)
  {
    OBMol* pmol = dynamic_cast<OBMol*>(pOb);
    if(pmol==NULL)
      return false;

    //Define some references so we can use the old parameter names
    ostream &ofs = *pConv->GetOutStream();
    OBMol &mol = *pmol;
    double fac = pConv->IsOption("n") ? 0.1 : 1.0; //new framework

    char type_name[16];
    char res_name[16];
    char buffer[BUFF_SIZE];
    string res_num;

    snprintf(buffer, BUFF_SIZE, "#GENERATED BY OPEN BABEL %s\n",BABEL_VERSION);
    ofs << buffer;

    /* GROMOS wants a TITLE block, so let's write one*/
    ofs << "TITLE\n" << mol.GetTitle() << "\nEND\n";
    ofs << "POSITION\n";

    OBAtom *atom;
    OBResidue *res;
    vector<OBAtom*>::iterator i;

    for(atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
      {
        if ( (res = atom->GetResidue()) )
          {
            // 16 = sizeof(res_name) and sizeof(type_name)
            strncpy(res_name,(char*)res->GetName().c_str(), 16);
            res_name[15] = '\0';
            strncpy(type_name,(char*)res->GetAtomID(atom).c_str(), 16);
            type_name[15] = '\0';
            res_num = res->GetNumString();
          }
        else
          {
            strncpy(type_name,OBElements::GetSymbol(atom->GetAtomicNum()), 16);
            strcpy(res_name,"UNK");
            res_num = "1";
          }

        snprintf(buffer, BUFF_SIZE, "%5s %5s %5s %6d %15.5f %15.5f %15.5f\n",
                res_num.c_str(),res_name,type_name,atom->GetIdx(),
                atom->x()*fac,atom->y()*fac,atom->z()*fac);
        ofs << buffer;

        if (!(atom->GetIdx()%10))
          {
            snprintf(buffer, BUFF_SIZE, "# %d\n",atom->GetIdx());
            ofs << buffer;
          }
      }

    ofs << "END\n";

    return(true);
  }
Exemple #27
0
  bool PDBFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
  {
    OBMol* pmol = dynamic_cast<OBMol*>(pOb);
    if(pmol==NULL)
      return false;

    //Define some references so we can use the old parameter names
    ostream &ofs = *pConv->GetOutStream();
    OBMol &mol = *pmol;

    unsigned int i;
    char buffer[BUFF_SIZE];
    char type_name[10], padded_name[10];
    char the_res[10];
    char the_chain = ' ';
    const char *element_name;
    int res_num;
    bool het=true;
    int model_num = 0;
    if (!pConv->IsLast() || pConv->GetOutputIndex() > 1)
      { // More than one molecule record
        model_num = pConv->GetOutputIndex(); // MODEL 1-based index
        snprintf(buffer, BUFF_SIZE, "MODEL %8d", model_num);
        ofs << buffer << endl;
      }

    // write back all fields (REMARKS, HELIX, SHEET, SITE, ...)
    bool compndWritten = false;
    bool authorWritten = false;
    std::vector<OBGenericData*> pairData = mol.GetAllData(OBGenericDataType::PairData);
    for (std::vector<OBGenericData*>::iterator data = pairData.begin(); data != pairData.end(); ++data) {
      OBPairData *pd = static_cast<OBPairData*>(*data);
      string attr = pd->GetAttribute();

      // filter to make sure we are writing pdb fields only
      if (attr != "HEADER" && attr != "OBSLTE" && attr != "TITLE" && attr != "SPLIT" &&
          attr != "CAVEAT" && attr != "COMPND" && attr != "SOURCE" && attr != "KEYWDS" &&
          attr != "EXPDTA" && attr != "NUMMDL" && attr != "MDLTYP" && attr != "AUTHOR" &&
          attr != "REVDAT" && attr != "SPRSDE" && attr != "JRNL" && attr != "REMARK" &&
          attr != "DBREF" && attr != "DBREF1" && attr != "DBREF2" && attr != "SEQADV" &&
          attr != "SEQRES" && attr != "MODRES" && attr != "HET" && attr != "HETNAM" &&
          attr != "HETSYN" && attr != "FORMUL" && attr != "HELIX" && attr != "SHEET" &&
          attr != "SSBOND" && attr != "LINK" && attr != "CISPEP" && attr != "SITE" &&
          attr != "ORIGX1" && attr != "ORIGX2" && attr != "ORIGX3" && attr != "SCALE1" &&
          attr != "SCALE2" && attr != "SCALE3" && attr != "MATRIX1" && attr != "MATRIX2" &&
          attr != "MATRIX3" && attr != "MODEL")
        continue;

      if (attr == "COMPND")
        compndWritten = true;
      if (attr == "AUTHOR")
        authorWritten = true;

      // compute spacing needed. HELIX, SITE, HET, ... are trimmed when reading
      int nSpacing = 6 - attr.size();
      for (int i = 0; i < nSpacing; ++i)
        attr += " ";


      std::string lines = pd->GetValue();
      string::size_type last = 0;
      string::size_type pos = lines.find('\n');
      while (last != string::npos) {
        string line = lines.substr(last, pos - last);
        if (pos == string::npos)
          last = string::npos;
        else
          last = pos + 1;
        pos = lines.find('\n', last);

        ofs << attr << line << endl;
      }
    }

    if (!compndWritten) {
      if (strlen(mol.GetTitle()) > 0)
        snprintf(buffer, BUFF_SIZE, "COMPND    %s ",mol.GetTitle());
      else
        snprintf(buffer, BUFF_SIZE, "COMPND    UNNAMED");
      ofs << buffer << endl;
    }

    if (!authorWritten) {
      snprintf(buffer, BUFF_SIZE, "AUTHOR    GENERATED BY OPEN BABEL %s",BABEL_VERSION);
      ofs << buffer << endl;
    }

    // Write CRYST1 record, containing unit cell parameters, space group
    // and Z value (supposed to be 1)
    if (pmol->HasData(OBGenericDataType::UnitCell))
      {
        OBUnitCell *pUC = (OBUnitCell*)pmol->GetData(OBGenericDataType::UnitCell);
        if(pUC->GetSpaceGroup()){
          string tmpHM=pUC->GetSpaceGroup()->GetHMName();
          // Do we have an extended HM symbol, with origin choice as ":1" or ":2" ? If so, remove it.
          size_t n=tmpHM.find(":");
          if(n!=string::npos) tmpHM=tmpHM.substr(0,n);
          snprintf(buffer, BUFF_SIZE,
                   "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s 1",
                   pUC->GetA(), pUC->GetB(), pUC->GetC(),
                   pUC->GetAlpha(), pUC->GetBeta(), pUC->GetGamma(),
                   tmpHM.c_str());
        }
        else
          snprintf(buffer, BUFF_SIZE,
                   "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s 1",
                   pUC->GetA(), pUC->GetB(), pUC->GetC(),
                   pUC->GetAlpha(), pUC->GetBeta(), pUC->GetGamma(),
                   "P1");

        ofs << buffer << endl;
      }

    // before we write any records, we should check to see if any coord < -1000
    // which will cause errors in the formatting

    double minX, minY, minZ;
    minX = minY = minZ = -999.0f;
    FOR_ATOMS_OF_MOL(a, mol)
      {
        if (a->GetX() < minX)
          minX = a->GetX();
        if (a->GetY() < minY)
          minY = a->GetY();
        if (a->GetZ() < minZ)
          minZ = a->GetZ();
      }
    vector3 transV = VZero;
    if (minX < -999.0)
      transV.SetX(-1.0*minX - 900.0);
    if (minY < -999.0)
      transV.SetY(-1.0*minY - 900.0);
    if (minZ < -999.0)
      transV.SetZ(-1.0*minZ - 900.0);

    // if minX, minY, or minZ was never changed, shift will be 0.0f
    // otherwise, move enough so that smallest coord is > -999.0f
    mol.Translate(transV);

    OBAtom *atom;
    OBResidue *res;
    for (i = 1; i <= mol.NumAtoms(); i++)
      {
        atom = mol.GetAtom(i);
        strncpy(type_name, etab.GetSymbol(atom->GetAtomicNum()), sizeof(type_name));
        type_name[sizeof(type_name) - 1] = '\0';

        //two char. elements are on position 13 and 14 one char. start at 14
        if (strlen(type_name) > 1)
          type_name[1] = toupper(type_name[1]);
        else
          {
            char tmp[10];
            strncpy(tmp, type_name, 9); // make sure to null-terminate tmp
            snprintf(type_name, sizeof(type_name), " %-3s", tmp);
          }

        if ( (res = atom->GetResidue()) != 0 )
          {
            het = res->IsHetAtom(atom);
            snprintf(the_res,4,"%s",(char*)res->GetName().c_str());
            the_res[4] = '\0';
            snprintf(type_name,5,"%s",(char*)res->GetAtomID(atom).c_str());
            the_chain = res->GetChain();

            //two char. elements are on position 13 and 14 one char. start at 14
            if (strlen(etab.GetSymbol(atom->GetAtomicNum())) == 1)
              {
                if (strlen(type_name) < 4)
                  {
                    char tmp[10];
                    strncpy(tmp, type_name, 9); // make sure to null-terminate tmp
                    snprintf(padded_name, sizeof(padded_name), " %-3s", tmp);
                    strncpy(type_name,padded_name,4);
                    type_name[4] = '\0';
                  }
                else
                  {
                    /*
                      type_name[4] = type_name[3];
                      type_name[3] = type_name[2];
                      type_name[2] = type_name[1];
                      type_name[1] = type_name[0];
                      type_name[0] = type_name[4];
                    */
                    type_name[4] = '\0';
                  }
              }
            res_num = res->GetNum();
          }
        else
          {
            strcpy(the_res,"UNK");
            the_res[3] = '\0';
            snprintf(padded_name,sizeof(padded_name), "%s",type_name);
            strncpy(type_name,padded_name,4);
            type_name[4] = '\0';
            res_num = 1;
          }

        element_name = etab.GetSymbol(atom->GetAtomicNum());

        int charge = atom->GetFormalCharge();
        char scharge[3] = { ' ', ' ', '\0' };
        if(0 != charge)
          {
            snprintf(scharge, 3, "%+d", charge);
            char tmp = scharge[1];
            scharge[1] = scharge[0];
            scharge[0] = tmp;
          }
        snprintf(buffer, BUFF_SIZE, "%s%5d %-4s %-3s %c%4d    %8.3f%8.3f%8.3f  1.00  0.00          %2s%2s\n",
                 het?"HETATM":"ATOM  ",
                 i,
                 type_name,
                 the_res,
                 the_chain,
                 res_num,
                 atom->GetX(),
                 atom->GetY(),
                 atom->GetZ(),
                 element_name,
                 scharge);
        ofs << buffer;
      }

    OBAtom *nbr;
    vector<OBBond*>::iterator k;
    for (i = 1; i <= mol.NumAtoms(); i ++)
      {
        atom = mol.GetAtom(i);
        if (atom->GetValence() == 0)
          continue; // no need to write a CONECT record -- no bonds

        snprintf(buffer, BUFF_SIZE, "CONECT%5d", i);
        ofs << buffer;
        // Write out up to 4 real bonds per line PR#1711154
        int currentValence = 0;
        for (nbr = atom->BeginNbrAtom(k);nbr;nbr = atom->NextNbrAtom(k))
          {
            snprintf(buffer, BUFF_SIZE, "%5d", nbr->GetIdx());
            ofs << buffer;
            if (++currentValence % 4 == 0) {
              // Add the trailing space to finish this record
              ofs << "                                       \n";
              // write the start of a new CONECT record
              snprintf(buffer, BUFF_SIZE, "CONECT%5d", i);
              ofs << buffer;
            }
          }

        // Add trailing spaces
        int remainingValence = atom->GetValence() % 4;
        for (int count = 0; count < (4 - remainingValence); count++) {
          snprintf(buffer, BUFF_SIZE, "     ");
          ofs << buffer;
        }
        ofs << "                                       \n";
      }

    snprintf(buffer, BUFF_SIZE, "MASTER        0    0    0    0    0    0    0    0 ");
    ofs << buffer;
    snprintf(buffer, BUFF_SIZE, "%4d    0 %4d    0\n",mol.NumAtoms(),mol.NumAtoms());
    ofs << buffer;

    ofs << "END\n";
    if (model_num) {
      ofs << "ENDMDL" << endl;
    }

    return(true);
  }
Exemple #28
0
  bool parseConectRecord(char *buffer,OBMol &mol)
  {
    stringstream errorMsg;
    string clearError;

    // Setup strings and string buffers
    vector<string> vs;
    buffer[70] = '\0';
    if (strlen(buffer) < 70)
      {
        errorMsg << "WARNING: Problems reading a PDB file\n"
                 << "  Problems reading a CONECT record.\n"
                 << "  According to the PDB specification,\n"
                 << "  the record should have 70 columns, but OpenBabel found "
                 << strlen(buffer) << " columns." << endl;
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obInfo);
        errorMsg.str(clearError);
      }

    // Serial number of the first atom, read from column 7-11 of the
    // connect record, to which the other atoms connect to.
    long int startAtomSerialNumber;
    // A pointer to the first atom.
    OBAtom *firstAtom = NULL;
    // Serial numbers of the atoms which bind to firstAtom, read from
    // columns 12-16, 17-21, 22-27 and 27-31 of the connect record. Note
    // that we reserve space for 5 integers, but read only four of
    // them. This is to simplify the determination of the bond order;
    // see below.
    long int boundedAtomsSerialNumbers[5]  = {0,0,0,0,0};
    // Bools which tell us which of the serial numbers in
    // boundedAtomsSerialNumbers are read from the file, and which are
    // invalid
    bool boundedAtomsSerialNumbersValid[5] = {false, false, false, false, false};

    // Pragmatic approach -- too many non-standard PDB files out there
    // (including some old ones from us)
    // So if we have a small number of atoms, then try to break by spaces
    // Otherwise (i.e., NumAtoms() > 9,999 we need to go by position)
    // We'll switch back and forth a few times to save duplicating common code

    if (mol.NumAtoms() <= 9999)
      {
        // make sure we don't look at salt bridges or whatever, so cut the buffer short
        buffer[32] = '\0';
        tokenize(vs,buffer);
        if( vs.empty() || vs.size() < 2)
          return false;
        vs.erase(vs.begin()); // remove "CONECT"

        startAtomSerialNumber = atoi(vs[0].c_str());
      }
    else
      {
        if (readIntegerFromRecord(buffer, 7, &startAtomSerialNumber) == false)
          {
            errorMsg << "WARNING: Problems reading a PDB file\n"
                     << "  Problems reading a CONECT record.\n"
                     << "  According to the PDB specification,\n"
                     << "  columns 7-11 should contain the serial number of an atom.\n"
                     << "  THIS CONECT RECORD WILL BE IGNORED." << endl;
            obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obWarning);
            return(false);
          }
      }

    vector<OBAtom*>::iterator i;
    for (OBAtom *a1 = mol.BeginAtom(i);a1;a1 = mol.NextAtom(i)) {
      // atoms may not have residue information, but if they do,
      // check serial numbers
      if (a1->GetResidue() != NULL &&
          static_cast<long int>(a1->GetResidue()->
                                GetSerialNum(a1)) == startAtomSerialNumber)
        {
          firstAtom = a1;
          break;
        }
    }

    if (firstAtom == NULL)
      {
        errorMsg << "WARNING: Problems reading a PDB file:\n"
                 << "  Problems reading a CONECT record.\n"
                 << "  According to the PDB specification,\n"
                 << "  columns 7-11 should contain the serial number of an atom.\n"
                 << "  No atom was found with this serial number.\n"
                 << "  THIS CONECT RECORD WILL BE IGNORED." << endl;
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obWarning);
        return(false);
      }

    if (mol.NumAtoms() < 9999)
      {
        if (vs.size() > 1) boundedAtomsSerialNumbers[0] = atoi(vs[1].c_str());
        if (vs.size() > 2) boundedAtomsSerialNumbers[1] = atoi(vs[2].c_str());
        if (vs.size() > 3) boundedAtomsSerialNumbers[2] = atoi(vs[3].c_str());
        if (vs.size() > 4) boundedAtomsSerialNumbers[3] = atoi(vs[4].c_str());

        unsigned int limit = 4;
        if (vs.size() <= 4)
          limit = vs.size() - 1;

        for (unsigned int s = 0; s < limit; ++s)
          boundedAtomsSerialNumbersValid[s] = true;
      }
    else
      {
        // Now read the serial numbers. If the first serial number is not
        // present, this connect record probably contains only hydrogen
        // bonds and salt bridges, which we ignore. In that case, we just
        // exit gracefully.
        boundedAtomsSerialNumbersValid[0] = readIntegerFromRecord(buffer, 12, boundedAtomsSerialNumbers+0);
        if (boundedAtomsSerialNumbersValid[0] == false)
          return(true);
        boundedAtomsSerialNumbersValid[1] = readIntegerFromRecord(buffer, 17, boundedAtomsSerialNumbers+1);
        boundedAtomsSerialNumbersValid[2] = readIntegerFromRecord(buffer, 22, boundedAtomsSerialNumbers+2);
        boundedAtomsSerialNumbersValid[3] = readIntegerFromRecord(buffer, 27, boundedAtomsSerialNumbers+3);
      }

    // Now iterate over the VALID boundedAtomsSerialNumbers and connect
    // the atoms.
    for(unsigned int k=0; boundedAtomsSerialNumbersValid[k]; k++)
      {
        // Find atom that is connected to, write an error message
        OBAtom *connectedAtom = 0L;
        for (OBAtom *a1 = mol.BeginAtom(i);a1;a1 = mol.NextAtom(i)) {
          // again, atoms may not have residues, but if they do, check serials
          if (a1->GetResidue() != NULL &&
              static_cast<long int>(a1->GetResidue()->
                                    GetSerialNum(a1)) == boundedAtomsSerialNumbers[k])
            {
              connectedAtom = a1;
              break;
            }
        }
        if (connectedAtom == 0L)
          {
            errorMsg << "WARNING: Problems reading a PDB file:\n"
                     << "  Problems reading a CONECT record.\n"
                     << "  According to the PDB specification,\n"
                     << "  Atoms with serial #" << startAtomSerialNumber
                     << " and #" << boundedAtomsSerialNumbers[k]
                     << " should be connected\n"
                     << "  However, an atom with serial #" << boundedAtomsSerialNumbers[k] << " was not found.\n"
                     << "  THIS CONECT RECORD WILL BE IGNORED." << endl;
            obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obWarning);
            return(false);
          }

        // Figure the bond order
        unsigned char order = 0;
        while(boundedAtomsSerialNumbersValid[k+order+1] && (boundedAtomsSerialNumbers[k+order]
                                                            == boundedAtomsSerialNumbers[k+order+1]))
          order++;
        k += order;

        // Generate the bond
        if (firstAtom->GetIdx() < connectedAtom->GetIdx()) { // record the bond 'in one direction' only
          OBBond *bond = mol.GetBond(firstAtom, connectedAtom);
          if (!bond)
            mol.AddBond(firstAtom->GetIdx(), connectedAtom->GetIdx(), order+1);
          else // An additional CONECT record with the same firstAtom that references
               // a bond created in the previous CONECT record.
               // For example, the 1136->1138 double bond in the following:
               //   CONECT 1136 1128 1137 1137 1138
               //   CONECT 1136 1138 1139
            bond->SetBondOrder(bond->GetBondOrder() + order+1);
        }

      }
    return(true);
  }
bool ChemDrawXMLFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
{
    static const xmlChar C_MOLECULE[]         = "fragment";
    static const xmlChar C_CDXML[]            = "CDXML";
    static const xmlChar C_BONDLENGTH[]       = "BondLength";
    static const xmlChar C_PAGE[]             = "page";
    static const xmlChar C_ATOM[]             = "n";
    static const xmlChar C_BOND[]             = "b";
    static const xmlChar C_ID[]               = "id";

    static const xmlChar C_CHARGE[]           = "Charge";
    static const xmlChar C_COORDS[]           = "p";
    static const xmlChar C_ELEMENT[]          = "Element";
    static const xmlChar C_ORDER[]            = "Order";
    static const xmlChar C_BEGIN[]            = "B";
    static const xmlChar C_END[]              = "E";
    static const xmlChar C_DISPLAY[]          = "Display";

    _pxmlConv = XMLConversion::GetDerived(pConv,false);
    if(!_pxmlConv)
        return false;

    OBMol* pmol = dynamic_cast<OBMol*>(pOb);
    if(pmol==NULL)
        return false;
    OBMol &mol = *pmol;

    OBBond *pbond;
    vector<OBBond*>::iterator j;
    if(_pxmlConv->GetOutputIndex() == 1)
    {
        xmlTextWriterStartDocument(writer(), NULL, NULL, NULL);
        xmlTextWriterWriteDTD(writer(), BAD_CAST "CDXML", NULL, BAD_CAST "http://www.camsoft.com/xml/cdxml.dtd", NULL);
        xmlTextWriterStartElement(writer(), C_CDXML);
        xmlTextWriterWriteFormatAttribute(writer(), C_BONDLENGTH , "30");
        xmlTextWriterStartElement(writer(), C_PAGE); // put everything on one page
        // now guess the average bond size for the first molecule and scale to 30.
        _scale = 0.;
        if (mol.NumBonds())
        {
            for (pbond = mol.BeginBond(j); pbond; pbond = mol.NextBond(j))
                _scale += pbond->GetLength();
            _scale /= mol.NumBonds();
        }
        else
            _scale = 1.; // FIXME: what happens if the molecule has no bond?
        _scale = 30. / _scale;
        _offset = 0;
    }

    xmlTextWriterStartElement(writer(), C_MOLECULE);

    OBAtom *patom;
    vector<OBAtom*>::iterator i;
    int n;
    for (patom = mol.BeginAtom(i); patom; patom = mol.NextAtom(i))
    {
        xmlTextWriterStartElement(writer(), C_ATOM);

        xmlTextWriterWriteFormatAttribute(writer(), C_ID , "%d", patom->GetIdx() + _offset);
        xmlTextWriterWriteFormatAttribute(writer(), C_COORDS , "%f %f", patom->GetX() * _scale, patom->GetY() * _scale);
        n = patom->GetAtomicNum();
        if (n != 6)
        {
            xmlTextWriterWriteFormatAttribute(writer(), C_ELEMENT , "%d", n);
        }
        n = patom->GetFormalCharge();
        if (n != 0)
        {
            xmlTextWriterWriteFormatAttribute(writer(), C_CHARGE , "%d", n);
        }
        xmlTextWriterEndElement(writer());
    }

    for (pbond = mol.BeginBond(j); pbond; pbond = mol.NextBond(j))
    {
        xmlTextWriterStartElement(writer(), C_BOND);
        patom = pbond->GetBeginAtom();
        xmlTextWriterWriteFormatAttribute(writer(), C_BEGIN , "%d", patom->GetIdx() + _offset);
        patom = pbond->GetEndAtom();
        xmlTextWriterWriteFormatAttribute(writer(), C_END , "%d", patom->GetIdx() + _offset);
        n = pbond->GetBO();
        if (n != 1)
        {
            xmlTextWriterWriteFormatAttribute(writer(), C_ORDER , "%d", n);
        }
        if (pbond->IsHash())
            xmlTextWriterWriteFormatAttribute(writer(), C_DISPLAY , "WedgeBegin");
        else if (pbond->IsWedge())
            xmlTextWriterWriteFormatAttribute(writer(), C_DISPLAY , "WedgedHashEnd");
        xmlTextWriterEndElement(writer());
    }
    _offset += mol.NumAtoms ();

    xmlTextWriterEndElement(writer());//molecule

    //TODO: Writing property block

    if(_pxmlConv->IsLast())
    {
        xmlTextWriterEndDocument(writer()); // page
        xmlTextWriterEndDocument(writer()); //document
        OutputToStream();
    }
    return true;
}
Exemple #30
0
  bool BGFFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
  {
    OBMol* pmol = dynamic_cast<OBMol*>(pOb);
    if(pmol==NULL)
      return false;

    //Define some references so we can use the old parameter names
    ostream &ofs = *pConv->GetOutStream();
    OBMol &mol = *pmol;

    vector<OBAtom*>::iterator i;
    int max_val;
    OBAtom *atom;
    char buffer[BUFF_SIZE];
    char elmnt_typ[8], dreid_typ[8], atm_sym[16], max_val_str[8];

    mol.Kekulize();

    ofs << "BIOGRF 200\n";
    snprintf(buffer, BUFF_SIZE, "DESCRP %s\n",mol.GetTitle());
    ofs << buffer;
    snprintf(buffer, BUFF_SIZE, "REMARK BGF file created by Open Babel %s\n",BABEL_VERSION);
    ofs << "FORCEFIELD DREIDING  \n";

    // write unit cell if available
    if (mol.HasData(OBGenericDataType::UnitCell))
      {
        OBUnitCell *uc = (OBUnitCell*)mol.GetData(OBGenericDataType::UnitCell);
        // e.g. CRYSTX    49.30287   49.23010   25.45631   90.00008   89.99995   57.10041
        snprintf(buffer, BUFF_SIZE,
                 "CRYSTX%12.5f%12.5f%12.5f%12.5f%12.5f%12.5f",
                 uc->GetA(), uc->GetB(), uc->GetC(),
                 uc->GetAlpha() , uc->GetBeta(), uc->GetGamma());
        ofs << buffer << "\n";
      }

    ofs << "FORMAT ATOM   (a6,1x,i5,1x,a5,1x,a3,1x,a1,1x,a5,3f10.5,1x,a5,i3,i2,1x,f8.5)\n";

    ttab.SetFromType("INT");

    for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
      {
        strncpy(elmnt_typ,etab.GetSymbol(atom->GetAtomicNum()), 7); // make sure to null-terminate
        elmnt_typ[sizeof(elmnt_typ) - 1] = '0';
        ToUpper(elmnt_typ);

        ttab.SetToType("DRE");
        ttab.Translate(dreid_typ,atom->GetType());
        ttab.SetToType("HAD");
        ttab.Translate(max_val_str,atom->GetType());
        max_val = atoi(max_val_str);
        if (max_val == 0)
          max_val = 1;
        snprintf(atm_sym,16,"%s%d",elmnt_typ,atom->GetIdx());
        snprintf(buffer,BUFF_SIZE,"%6s %5d %-5s %3s %1s %5s%10.5f%10.5f%10.5f %-5s%3d%2d %8.5f\n",
                "HETATM",
                atom->GetIdx(),
                atm_sym,
                "RES",
                "A",
                "444",
                atom->GetX(),
                atom->GetY(),
                atom->GetZ(),
                dreid_typ,
                max_val,
                0,
                atom->GetPartialCharge());
        ofs << buffer;
      }
    ofs<< "FORMAT CONECT (a6,12i6)\n\n";

    OBAtom *nbr;
    vector<OBBond*>::iterator j;
    for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
      if (atom->GetValence())
        {
          snprintf(buffer,BUFF_SIZE,"CONECT%6d",atom->GetIdx());
          ofs << buffer;
          for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j))
            {
              snprintf(buffer,BUFF_SIZE,"%6d",nbr->GetIdx());
              ofs << buffer;
            }
          ofs << endl;

          snprintf(buffer,BUFF_SIZE,"ORDER %6d",atom->GetIdx());
          ofs << buffer;
          for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j))
            {
              snprintf(buffer,BUFF_SIZE,"%6d",(*j)->GetBO());
              ofs << buffer;
            }
          ofs << endl;
        }

    ofs << "END" << endl;
    return(true);
  }