Example #1
0
  unsigned int GetAtomSymClass(OBAtom *atom)
  {
    OBPairData *pd = dynamic_cast<OBPairData*>(atom->GetParent()->GetData("OpenBabel Symmetry Classes"));
    if (pd) {

      cout << "same? = " << pd->GetValue() << endl;

      istringstream iss(pd->GetValue());
      std::vector<unsigned int> symmetry_classes;
      copy(istream_iterator<unsigned int>(iss),
           istream_iterator<unsigned int>(),
           back_inserter<vector<unsigned int> >(symmetry_classes));
      // Now find the number of unique elements
      vector<unsigned int> copy_sym = symmetry_classes;
      sort(copy_sym.begin(), copy_sym.end());
      vector<unsigned int>::iterator end_pos = unique(copy_sym.begin(), copy_sym.end()); // Requires sorted elements
      int nclasses = end_pos - copy_sym.begin();

      cout << "sym_class[" << atom->GetIndex() << "] = " << symmetry_classes.at(atom->GetIndex()) << endl;
      return symmetry_classes.at(atom->GetIndex());
    }

    return 99;
  }
Example #2
0
  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);
  }
Example #3
0
bool TinkerFormat::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 mmffTypes = pConv->IsOption("m",OBConversion::OUTOPTIONS) != NULL;

    unsigned int i;
    char buffer[BUFF_SIZE];
    OBBond *bond;
    vector<OBBond*>::iterator j;

    // Before we try output of MMFF94 atom types, check if it works
    OBForceField *ff = OpenBabel::OBForceField::FindForceField("MMFF94");
    if (mmffTypes && ff && ff->Setup(mol))
      mmffTypes = ff->GetAtomTypes(mol);
    else
      mmffTypes = false; // either the force field isn't available, or it doesn't work

    if (!mmffTypes)
      snprintf(buffer, BUFF_SIZE, "%6d %-20s   MM2 parameters\n",mol.NumAtoms(),mol.GetTitle());
    else
      snprintf(buffer, BUFF_SIZE, "%6d %-20s   MMFF94 parameters\n",mol.NumAtoms(),mol.GetTitle());
    ofs << buffer;

    ttab.SetFromType("INT");

    OBAtom *atom;
    string str,str1;
    for(i = 1;i <= mol.NumAtoms(); i++)
    {
        atom = mol.GetAtom(i);
        str = atom->GetType();
        ttab.SetToType("MM2");
        ttab.Translate(str1,str);

        if (mmffTypes) {
          // Override the MM2 typing
          OBPairData *type = (OpenBabel::OBPairData*)atom->GetData("FFAtomType");
          if (type)
            str1 = type->GetValue().c_str();
        }

        snprintf(buffer, BUFF_SIZE, "%6d %2s  %12.6f%12.6f%12.6f %5d",
                i,
                etab.GetSymbol(atom->GetAtomicNum()),
                atom->GetX(),
                atom->GetY(),
                atom->GetZ(),
                atoi((char*)str1.c_str()));
        ofs << buffer;

        for (bond = atom->BeginBond(j); bond; bond = atom->NextBond(j))
        {
            snprintf(buffer, BUFF_SIZE, "%6d", (bond->GetNbrAtom(atom))->GetIdx());
            ofs << buffer;
        }

        ofs << endl;
    }

    return(true);
}
Example #4
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);
  }
Example #5
0
int main(int argc,char *argv[])
{
  // turn off slow sync with C-style output (we don't use it anyway).
  std::ios::sync_with_stdio(false);

  OBConversion conv;
  OBFormat *inFormat, *canFormat;
  OBMol mol;
  ifstream ifs;
  vector<OBMol> fragments;
  unsigned int fragmentCount = 0; // track how many in library -- give a running count
  map<string, int> index; // index of cansmi
  string currentCAN;
  unsigned int size;
  OBAtom *atom;
  OBBond *bond;
  bool nonRingAtoms, nonRingBonds;
  char buffer[BUFF_SIZE];

  canFormat = conv.FindFormat("can");
  conv.SetOutFormat(canFormat);

  if (argc < 2)
    {
      cout << "Usage: obfragment <file>" << endl;
      return(-1);
    }

  for (int i = 1; i < argc; i++) {
    cerr << " Reading file " << argv[i] << endl;

    inFormat = conv.FormatFromExt(argv[i]);
    if(inFormat==NULL || !conv.SetInFormat(inFormat))
      {
        cerr << " Cannot read file format for " << argv[i] << endl;
        continue; // try next file
      }
    
    ifs.open(argv[i]);
    
    if (!ifs)
      {
        cerr << "Cannot read input file: " << argv[i] << endl;
        continue;
      }
    
    
    while(ifs.peek() != EOF && ifs.good())
      {
        conv.Read(&mol, &ifs);
        if (!mol.Has3D()) continue; // invalid coordinates!
        mol.DeleteHydrogens(); // remove these before we do anything else
        
        do {
          nonRingAtoms = false;
          size = mol.NumAtoms();
          for (unsigned int i = 1; i <= size; ++i)
            {
              atom = mol.GetAtom(i);
              if (!atom->IsInRing()) {
                mol.DeleteAtom(atom);
                nonRingAtoms = true;
                break; // don't know how many atoms there are
              } 
              // Previously, we changed atoms to carbon here.
              // Now we perform this alchemy in terms of string-rewriting
              // once the canonical SMILES is generated
            }
        } while (nonRingAtoms);
        
        if (mol.NumAtoms() < 3)
          continue;
        
        if (mol.NumBonds() == 0)
          continue;
        
        do {
          nonRingBonds = false;
          size = mol.NumBonds();
          for (unsigned int i = 0; i < size; ++i)
            {
              bond = mol.GetBond(i);
              if (!bond->IsInRing()) {
                mol.DeleteBond(bond);
                nonRingBonds = true;
                break; // don't know how many bonds there are
              }
            }        
        } while (nonRingBonds);

        fragments = mol.Separate();
        for (unsigned int i = 0; i < fragments.size(); ++i)
          {
            if (fragments[i].NumAtoms() < 3) // too small to care
              continue;
              
            currentCAN = conv.WriteString(&fragments[i], true);
            currentCAN = RewriteSMILES(currentCAN); // change elements to "a/A" for compression
            if (index.find(currentCAN) != index.end()) { // already got this
              index[currentCAN] += 1; // add to the count for bookkeeping
              continue;
            }

            index[currentCAN] = 1; // don't ever write this ring fragment again

            // OK, now retrieve the canonical ordering for the fragment
            vector<string> canonical_order;
            if (fragments[i].HasData("Canonical Atom Order")) {
              OBPairData *data = (OBPairData*)fragments[i].GetData("Canonical Atom Order");
              tokenize(canonical_order, data->GetValue().c_str());
            }

            // Write out an XYZ-style file with the CANSMI as the title
            cout << fragments[i].NumAtoms() << '\n';
            cout << currentCAN << '\n'; // endl causes a flush

            vector<string>::iterator can_iter;
            unsigned int order;
            OBAtom *atom;

            fragments[i].Center();
            fragments[i].ToInertialFrame();

            for (unsigned int index = 0; index < canonical_order.size(); 
                 ++index) {
              order = atoi(canonical_order[index].c_str());
              atom = fragments[i].GetAtom(order);
              
              snprintf(buffer, BUFF_SIZE, "C%8.3f%8.3f%8.3f\n",
                       atom->x(), atom->y(), atom->z());
              cout << buffer;
            }

          }
        fragments.clear();
        if (index.size() > fragmentCount) {
          fragmentCount = index.size();
          cerr << " Fragments: " << fragmentCount << endl;
        }

      } // while reading molecules (in this file)
    ifs.close();
    ifs.clear();
  } // while reading files

  // loop through the map and output frequencies
  map<string, int>::const_iterator indexItr;
  for (indexItr = index.begin(); indexItr != index.end(); ++indexItr) {
    cerr << (*indexItr).second << " INDEX " << (*indexItr).first << "\n";
  }
    
  return(0);
}
Example #6
0
  bool TinkerFormat::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 mm2Types = false;
    bool mmffTypes = pConv->IsOption("m",OBConversion::OUTOPTIONS) != NULL;
    bool mm3Types = pConv->IsOption("3",OBConversion::OUTOPTIONS) != NULL;
    bool classTypes = pConv->IsOption("c", OBConversion::OUTOPTIONS) != NULL;

    unsigned int i;
    char buffer[BUFF_SIZE];
    OBBond *bond;
    vector<OBBond*>::iterator j;

    // Before we try output of MMFF94 atom types, check if it works
    OBForceField *ff = OpenBabel::OBForceField::FindForceField("MMFF94");
    if (mmffTypes && ff && ff->Setup(mol))
      mmffTypes = ff->GetAtomTypes(mol);
    else
      mmffTypes = false; // either the force field isn't available, or it doesn't work

    if (!mmffTypes && !mm3Types && !classTypes) {
      snprintf(buffer, BUFF_SIZE, "%6d %-20s   MM2 parameters\n",mol.NumAtoms(),mol.GetTitle());
      mm2Types = true;
    }
    else if (mm3Types)
      snprintf(buffer, BUFF_SIZE, "%6d %-20s   MM3 parameters\n",mol.NumAtoms(),mol.GetTitle());
    else if (classTypes)
      snprintf(buffer, BUFF_SIZE, "%6d %-20s   Custom parameters\n",mol.NumAtoms(),mol.GetTitle());
    else
      snprintf(buffer, BUFF_SIZE, "%6d %-20s   MMFF94 parameters\n",mol.NumAtoms(),mol.GetTitle());
    ofs << buffer;

    ttab.SetFromType("INT");

    OBAtom *atom;
    string str,str1;
    int atomType;
    for(i = 1;i <= mol.NumAtoms(); i++)
      {
        atom = mol.GetAtom(i);
        str = atom->GetType();
        atomType = 0; // Something is very wrong if this doesn't get set below

        if (mm2Types) {
          ttab.SetToType("MM2");
          ttab.Translate(str1,str);
          atomType = atoi((char*)str1.c_str());
        }
        if (mmffTypes) {
          // Override the MM2 typing
          OBPairData *type = (OpenBabel::OBPairData*)atom->GetData("FFAtomType");
          if (type) {
            str1 = type->GetValue().c_str();
            atomType = atoi((char*)str1.c_str());
          }
        }
        if (mm3Types) {
          // convert to integer for MM3 typing
          atomType = SetMM3Type(atom);
        }
        if (classTypes) {
          // Atom classes are set by the user, so use those
          OBGenericData *data = atom->GetData("Atom Class");
          if (data) {
            OBPairInteger* acdata = dynamic_cast<OBPairInteger*>(data); // Could replace with C-style cast if willing to live dangerously
            if (acdata) {
              int ac = acdata->GetGenericValue();
              if (ac >= 0)
                atomType = ac;
            }
          }
        }

        snprintf(buffer, BUFF_SIZE, "%6d %2s  %12.6f%12.6f%12.6f %5d",
                 i,
                 OBElements::GetSymbol(atom->GetAtomicNum()),
                 atom->GetX(),
                 atom->GetY(),
                 atom->GetZ(),
                 atomType);
        ofs << buffer;

        for (bond = atom->BeginBond(j); bond; bond = atom->NextBond(j))
          {
            snprintf(buffer, BUFF_SIZE, "%6d", (bond->GetNbrAtom(atom))->GetIdx());
            ofs << buffer;
          }

        ofs << endl;
      }

    return(true);
  }
void mmff94_validate()
{
  OBForceField* pFF = OBForceField::FindForceField("MMFF94");

  OBConversion conv;
  OBFormat *format_in = conv.FindFormat("mol2");
  vector<string> vs;
  vector<int> types;
  vector<double> fcharges, pcharges;
  vector<double> bond_lengths;
  char buffer[BUFF_SIZE], _logbuf[BUFF_SIZE];
  bool molfound, atomfound, bondfound, fchgfound, pchgfound;
  double etot, ebond, eangle, eoop, estbn, etor, evdw, eeq;
  double termcount; //1=bond, 2=angle, 3=strbnd, 4=torsion, 5=oop
  int n = 0;

  BOOST_REQUIRE_MESSAGE( format_in && conv.SetInFormat(format_in), "Could not set mol2 input format" );

  ifstream ifs, ifs2;
  ofstream ofs;

  ifs.open("MMFF94_dative.mol2");
  BOOST_REQUIRE_MESSAGE( ifs, "Could not open ./MMFF94_dative.mol2" );
 
  ifs2.open("MMFF94_opti.log");
  BOOST_REQUIRE_MESSAGE( ifs2, "Could not open ./MMFF94_opti.log" );
    
  ofs.open("MMFF94_openbabel.log");
  BOOST_REQUIRE_MESSAGE( ofs, "Could not open ./MMFF94_openbabel.log" );
    
  pFF->SetLogFile(&ofs);
  pFF->SetLogLevel(OBFF_LOGLVL_HIGH);
   
  OBMol mol;
  for (unsigned int c=1;; c++) {
    mol.Clear();
    types.clear();
    fcharges.clear();
    pcharges.clear();
    bond_lengths.clear();

    if (!conv.Read(&mol, &ifs))
      break;
    if (mol.Empty())
      break;
     
    BOOST_CHECK_MESSAGE( pFF->Setup(mol), "Could not setup calculations (missing parameters...)" );

    pFF->GetAtomTypes(mol);
    //pFF->GetFormalCharges(mol);
    pFF->GetPartialCharges(mol);

    termcount = 0;
    molfound = false;
    atomfound = false;
    bondfound = false;
    fchgfound = false;
    pchgfound = false;

    // Parse log file for types, charges, energies, ..
    while (ifs2.getline(buffer, 150)) {
      tokenize(vs, buffer);
      if (vs.size() == 0) {
        bondfound = false;
        continue;
      }
	
      string str(buffer);
      if (string::npos != str.find(mol.GetTitle(),0))
        molfound = true;

      // read atom types
      if (atomfound) {
        if (n) {
          types.push_back(atoi(vs[2].c_str()));
          types.push_back(atoi(vs[5].c_str()));
          types.push_back(atoi(vs[8].c_str()));
          types.push_back(atoi(vs[11].c_str()));
        } else {
          if (vs.size() > 2)
            types.push_back(atoi(vs[2].c_str()));
          if (vs.size() > 5)
            types.push_back(atoi(vs[5].c_str()));
          if (vs.size() > 8)
            types.push_back(atoi(vs[8].c_str()));
   
          atomfound = false;
        }
        n--;
      }
        
      // read formal charges
      if (fchgfound) {
        if (n) {
          fcharges.push_back(atof(vs[2].c_str()));
          fcharges.push_back(atof(vs[5].c_str()));
          fcharges.push_back(atof(vs[8].c_str()));
          fcharges.push_back(atof(vs[11].c_str()));
        } else {
          if (vs.size() > 2)
            fcharges.push_back(atof(vs[2].c_str()));
          if (vs.size() > 5)
            fcharges.push_back(atof(vs[5].c_str()));
          if (vs.size() > 8)
            fcharges.push_back(atof(vs[8].c_str()));
   
          fchgfound = false;
        }
        n--;
      }
 
      // read partial charges
      if (pchgfound) {
        if (n) {
          pcharges.push_back(atof(vs[2].c_str()));
          pcharges.push_back(atof(vs[5].c_str()));
          pcharges.push_back(atof(vs[8].c_str()));
          pcharges.push_back(atof(vs[11].c_str()));
        } else {
          if (vs.size() > 2)
            pcharges.push_back(atof(vs[2].c_str()));
          if (vs.size() > 5)
            pcharges.push_back(atof(vs[5].c_str()));
          if (vs.size() > 8)
            pcharges.push_back(atof(vs[8].c_str()));
   
          pchgfound = false;
        }
        n--;
      }
 
      // identify blocks
      if (molfound && EQn(buffer, " ATOM NAME  TYPE", 16)) {
        atomfound = true;
        n = mol.NumAtoms() / 4;
      }
      if (molfound && EQn(buffer, "   ATOM   FCHARGE", 17)) {
        fchgfound = true;
        n = mol.NumAtoms() / 4;
      }
      if (molfound && EQn(buffer, "   ATOM    CHARGE", 17)) {
        pchgfound = true;
        n = mol.NumAtoms() / 4;
      }

      if (bondfound)
        bond_lengths.push_back(atof(vs[7].c_str()));

      // Get the energies
      if (molfound) {
        if (EQn(buffer, " Total ENERGY", 13))
          etot = atof(vs[3].c_str());
        if (EQn(buffer, " Bond Stretching", 16))
          ebond = atof(vs[2].c_str());
        if (EQn(buffer, " Angle Bending", 14))
          eangle = atof(vs[2].c_str());
        if (EQn(buffer, " Out-of-Plane Bending", 21))
          eoop = atof(vs[2].c_str());
        if (EQn(buffer, " Stretch-Bend", 13))
          estbn = atof(vs[1].c_str());
        if (EQn(buffer, "     Total Torsion", 18))
          etor = atof(vs[2].c_str());
        if (EQn(buffer, "     Net vdW", 12))
          evdw = atof(vs[2].c_str());
        if (EQn(buffer, " Electrostatic", 14))
          eeq = atof(vs[1].c_str());
        if (EQn(buffer, " ---------------------", 22) && (termcount == 0)) {
          termcount++;
        bondfound = true;
        }
        if (EQn(buffer, " OPTIMOL>  # read next", 22))
          break;
      }
    } // while (getline)
      
    ostringstream os;
    vector<int>::iterator i;
    vector<double>::iterator di;
    unsigned int ni;
    bool failed;

    cout << "--------------------------------------------------------------------------------" << endl;
    cout << "                                                                                " << endl;
    cout << "  VALIDATE MOLECULE " << c << ": " << mol.GetTitle() << endl;
    cout << "                                                                                " << endl;
    cout << "IDX  HYB  AROM  OB_TYPE  LOG_TYPE       RESULT                                  " << endl;
    cout << "----------------------------------------------                                  " << endl;
 
    // 
    // validate atom types
    //
    ni = 1;
    failed = false;
    for (i = types.begin(); i != types.end();i++) {
      if (ni > mol.NumAtoms())
        continue;

      OBPairData *type = (OBPairData*) mol.GetAtom(ni)->GetData("FFAtomType");
      if (!type)
	continue;

      os.str("");
      os << "In molecule " << mol.GetTitle() << ": Wrong atom type for atom ";
      os << ni << " # found " << type->GetValue() << ", expected " << *i;
      BOOST_CHECK_MESSAGE( atoi(type->GetValue().c_str()) == (*i), os.str().c_str());
      
      if (atoi(type->GetValue().c_str()) == (*i))
        snprintf(_logbuf, BUFF_SIZE, "%2d   %3d  %4d    %3d      %3d          PASSED", 
                  mol.GetAtom(ni)->GetIdx(), mol.GetAtom(ni)->GetHyb(), 
                  mol.GetAtom(ni)->IsAromatic(), atoi(mol.GetAtom(ni)->GetType()), *i);
      else {
        snprintf(_logbuf, BUFF_SIZE, "%2d   %3d  %4d    %3d      %3d      XXX FAILED XXX", 
                  mol.GetAtom(ni)->GetIdx(), mol.GetAtom(ni)->GetHyb(), 
                  mol.GetAtom(ni)->IsAromatic(), atoi(type->GetValue().c_str()), *i);
        failed = true;
      }
      
      cout << _logbuf << endl;
        
      ni++;
    }

    /*
    cout << endl;
    cout << "IDX  OB_FCARGE  LOG_FCHARGE       RESULT" << endl;
    cout << "----------------------------------------" << endl;
            
    // 
    // validate formal charges
    //
    ni = 1;
    for (di = fcharges.begin(); di != fcharges.end(); di++) {
      if (ni > mol.NumAtoms())
        continue;
	
      if (fabs((*di) - mol.GetAtom(ni)->GetPartialCharge()) <= 0.001)
        snprintf(_logbuf, BUFF_SIZE, "%2d   %7.4f     %7.4f          PASSED", mol.GetAtom(ni)->GetIdx(), mol.GetAtom(ni)->GetPartialCharge(), *di);
      else {
        snprintf(_logbuf, BUFF_SIZE, "%2d   %7.4f     %7.4f      XXX FAILED XXX", mol.GetAtom(ni)->GetIdx(), mol.GetAtom(ni)->GetPartialCharge(), *di);
        failed = true;
      }
      
      cout << _logbuf << endl;
        
      ni++;
    }

    */

    cout << endl;
    cout << "IDX  OB_PCARGE  LOG_PCHARGE       RESULT" << endl;
    cout << "----------------------------------------" << endl;
      
    // 
    // validate partial charges
    //
    ni = 1;
    for (di = pcharges.begin(); di != pcharges.end(); di++) {
      if (ni > mol.NumAtoms())
        continue;
	
      OBPairData *chg = (OBPairData*) mol.GetAtom(ni)->GetData("FFPartialCharge");
      if (!chg)
	continue;

      os.str("");
      os << "In molecule " << mol.GetTitle() << ": Wrong partial charge for atom ";
      os << ni << " # found " << chg->GetValue() << ", expected " << *di;
      BOOST_CHECK_MESSAGE( fabs((*di) - atof(chg->GetValue().c_str())) <= 0.001, os.str().c_str());

      if (fabs((*di) - atof(chg->GetValue().c_str())) <= 0.001)
        snprintf(_logbuf, BUFF_SIZE, "%2d   %7.4f     %7.4f          PASSED", 
		  mol.GetAtom(ni)->GetIdx(), atof(chg->GetValue().c_str()), *di);
      else {
        snprintf(_logbuf, BUFF_SIZE, "%2d   %7.4f     %7.4f      XXX FAILED XXX",
                  mol.GetAtom(ni)->GetIdx(), atof(chg->GetValue().c_str()), *di);
        failed = true;
      }
      
      cout << _logbuf << endl;
        
      ni++;
    }

    double ene, delta;
    cout << endl;
    cout << "TERM                     OB ENERGY     LOG ENERGY         DELTA" << endl;
    cout << "---------------------------------------------------------------" << endl;
 
    // 
    // validate energies
    //
    
    // bond stretching
    ene = pFF->E_Bond();
    delta = (ene - ebond);
    
    os.str("");
    os << "In molecule " << mol.GetTitle() << ": Wrong bond stretching energy ";
    os << " # found " << ene << ", expected " << ebond;
    BOOST_CHECK_MESSAGE( delta < 0.005, os.str().c_str());

    snprintf(_logbuf, BUFF_SIZE, "Bond Stretching        %11.5f    %11.5f   %11.5f", ene, ebond, delta);
    cout << _logbuf << endl;
    
    // angle bending
    ene = pFF->E_Angle();
    delta = (ene - eangle);

    os.str("");
    os << "In molecule " << mol.GetTitle() << ": Wrong angle bending energy ";
    os << " # found " << ene << ", expected " << eangle;
    BOOST_CHECK_MESSAGE( delta < 0.005, os.str().c_str());

    snprintf(_logbuf, BUFF_SIZE, "Angle Bending          %11.5f    %11.5f   %11.5f", ene, eangle, delta);
    cout << _logbuf << endl;
    
    // stretch bending
    ene = pFF->E_StrBnd();
    delta = (ene - estbn);

    os.str("");
    os << "In molecule " << mol.GetTitle() << ": Wrong stretch bending energy ";
    os << " # found " << ene << ", expected " << estbn;
    BOOST_CHECK_MESSAGE( delta < 0.005, os.str().c_str());

    snprintf(_logbuf, BUFF_SIZE, "Stretch-Bending        %11.5f    %11.5f   %11.5f", ene, estbn, delta);
    cout << _logbuf << endl;
    
    // OOP
    ene = pFF->E_OOP();
    delta = (ene - eoop);

    os.str("");
    os << "In molecule " << mol.GetTitle() << ": Wrong out-of-plane bending energy ";
    os << " # found " << ene << ", expected " << eoop;
    BOOST_CHECK_MESSAGE( delta < 0.005, os.str().c_str());

    snprintf(_logbuf, BUFF_SIZE, "Out-Of-Plane Bending   %11.5f    %11.5f   %11.5f", ene, eoop, delta);
    cout << _logbuf << endl;
    
    // Torsional
    ene = pFF->E_Torsion();
    delta = (ene - etor);

    os.str("");
    os << "In molecule " << mol.GetTitle() << ": Wrong torsional energy ";
    os << " # found " << ene << ", expected " << etor;
    BOOST_CHECK_MESSAGE( delta < 0.005, os.str().c_str());
 
    snprintf(_logbuf, BUFF_SIZE, "Torsional              %11.5f    %11.5f   %11.5f", ene, etor, delta);
    cout << _logbuf << endl;
    
    // VDW
    ene = pFF->E_VDW();
    delta = (ene - evdw);

    os.str("");
    os << "In molecule " << mol.GetTitle() << ": Wrong van der waals energy ";
    os << " # found " << ene << ", expected " << evdw;
    BOOST_CHECK_MESSAGE( delta < 0.005, os.str().c_str());
 
    snprintf(_logbuf, BUFF_SIZE, "Van der Waals          %11.5f    %11.5f   %11.5f", ene, evdw, delta);
    cout << _logbuf << endl;
      
    // Electrostatic 
    ene = pFF->E_Electrostatic();
    delta = (ene - eeq);

    os << "In molecule " << mol.GetTitle() << ": Wrong electrostatic energy ";
    os << " # found " << ene << ", expected " << eeq;
    BOOST_CHECK_MESSAGE( delta < 0.005, os.str().c_str());
 
    snprintf(_logbuf, BUFF_SIZE, "Electrostatic          %11.5f    %11.5f   %11.5f", ene, eeq, delta);
    cout << _logbuf << endl;

    cout << endl;
    ene = pFF->Energy();
    delta = (ene - etot);

    os.str("");
    os << "In molecule " << mol.GetTitle() << ": Wrong total energy ";
    os << " # found " << ene << ", expected " << etot;
    BOOST_CHECK_MESSAGE( delta < 0.005, os.str().c_str());
 
    snprintf(_logbuf, BUFF_SIZE, "Total ENERGY           %11.5f    %11.5f   %11.5f", ene, etot, delta);
    cout << _logbuf << endl;

  } // for (unsigned int c;; c++ )
   
  if (ifs)
    ifs.close();
  if (ifs2)
    ifs2.close();
  if (ofs)
    ofs.close();
}