void MoleculeInChI::_normalizeMolecule(Molecule &mol)
{
   QS_DEF(Array<int>, ignored);

   ignored.clear_resize(mol.vertexEnd());
   ignored.zerofill();

   for (int i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i))
      if (mol.convertableToImplicitHydrogen(i))
         ignored[i] = 1;

   for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i))
      if (mol.getBondTopology(i) == TOPOLOGY_RING)
         mol.cis_trans.setParity(i, 0);
   
   MoleculeAutomorphismSearch of;

   of.detect_invalid_cistrans_bonds = true;
   of.detect_invalid_stereocenters = true;
   of.find_canonical_ordering = false;
   of.ignored_vertices = ignored.ptr();
   of.process(mol);

   for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i))
      if (mol.cis_trans.getParity(i) != 0 && of.invalidCisTransBond(i))
         mol.cis_trans.setParity(i, 0);

   for (int i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
      if (mol.stereocenters.getType(i) > MoleculeStereocenters::ATOM_ANY && of.invalidStereocenter(i))
         mol.stereocenters.remove(i);
   
}
Beispiel #2
0
void CanonicalSmilesSaver::saveMolecule (Molecule &mol_) const
{
   if (mol_.vertexCount() < 1)
      return;

   QS_DEF(Array<int>, ignored);
   QS_DEF(Array<int>, order);
   QS_DEF(Array<int>, ranks);
   QS_DEF(Molecule, mol);
   int i;

   if (mol_.repeating_units.size() > 0)
      throw Error("can not canonicalize a polymer");

   // Detect hydrogens configuration if aromatic but not ambiguous
   bool found_invalid_h = false;
   for (i = mol_.vertexBegin(); i != mol_.vertexEnd(); i = mol_.vertexNext(i))
   {
      if (mol_.isRSite(i) || mol_.isPseudoAtom(i))
         continue;

      if (mol_.getImplicitH_NoThrow(i, -1) == -1)
         found_invalid_h = true;
   }
   if (found_invalid_h)
   {
      AromaticityOptions options;
      options.method = AromaticityOptions::GENERIC;
      options.unique_dearomatization = true;
      MoleculeDearomatizer::restoreHydrogens(mol_, options);
   }

   mol.clone(mol_, 0, 0);

   // TODO: canonicalize allenes properly
   mol.allene_stereo.clear();

   ignored.clear_resize(mol.vertexEnd());
   ignored.zerofill();

   for (i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i))
      if (mol.convertableToImplicitHydrogen(i))
         ignored[i] = 1;

   for (i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i))
      if (mol.getBondTopology(i) == TOPOLOGY_RING && mol.cis_trans.getParity(i) != 0)
      {
         // we save cis/trans ring bonds into SMILES, but only those who
         // do not participate in bigger ring systems
         const Edge &edge = mol.getEdge(i);

         if (mol.getAtomRingBondsCount(edge.beg) != 2 ||
             mol.getAtomRingBondsCount(edge.end) != 2)
         {
            mol.cis_trans.setParity(i, 0);
            continue;
         }

         // also, discard the cis-trans bonds that have been converted to aromatic
         const Vertex &beg = mol.getVertex(edge.beg);
         const Vertex &end = mol.getVertex(edge.end);
         bool have_singlebond_beg = false;
         bool have_singlebond_end = false;
         int j;
         
         for (j = beg.neiBegin(); j != beg.neiEnd(); j = beg.neiNext(j))
            if (mol.getBondOrder(beg.neiEdge(j)) == BOND_SINGLE)
               have_singlebond_beg = true;

         for (j = end.neiBegin(); j != end.neiEnd(); j = end.neiNext(j))
            if (mol.getBondOrder(end.neiEdge(j)) == BOND_SINGLE)
               have_singlebond_end = true;

         if (!have_singlebond_beg || !have_singlebond_end)
         {
            mol.cis_trans.setParity(i, 0);
            continue;
         }
      }
         
   MoleculeAutomorphismSearch of;

   of.detect_invalid_cistrans_bonds = find_invalid_stereo;
   of.detect_invalid_stereocenters = find_invalid_stereo;
   of.find_canonical_ordering = true;
   of.ignored_vertices = ignored.ptr();
   of.process(mol);
   of.getCanonicalNumbering(order);

   for (i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i))
      if (mol.cis_trans.getParity(i) != 0 && of.invalidCisTransBond(i))
         mol.cis_trans.setParity(i, 0);

   for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
      if (mol.stereocenters.getType(i) > MoleculeStereocenters::ATOM_ANY && of.invalidStereocenter(i))
         mol.stereocenters.remove(i);

   ranks.clear_resize(mol.vertexEnd());

   for (i = 0; i < order.size(); i++)
      ranks[order[i]] = i;

   SmilesSaver saver(_output);

   saver.ignore_invalid_hcount = false;
   saver.vertex_ranks = ranks.ptr();
   saver.ignore_hydrogens = true;
   saver.canonize_chiralities = true;
   saver.saveMolecule(mol);
}
Beispiel #3
0
void CanonicalSmilesSaver::saveMolecule (Molecule &mol_)
{
   if (mol_.vertexCount() < 1)
      return;

   QS_DEF(Array<int>, ignored);
   QS_DEF(Array<int>, order);
   QS_DEF(Array<int>, ranks);
   QS_DEF(Molecule, mol);

   int i;

   if (mol_.sgroups.isPolimer())
      throw Error("can not canonicalize a polymer");

   // Detect hydrogens configuration if aromatic but not ambiguous
   // We can store this infromation in the original structure mol_.
   mol_.restoreAromaticHydrogens();

   mol.clone(mol_, 0, 0);

   // TODO: canonicalize allenes properly
   mol.allene_stereo.clear();

   ignored.clear_resize(mol.vertexEnd());
   ignored.zerofill();

   for (i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i))
      if (mol.convertableToImplicitHydrogen(i))
         ignored[i] = 1;

   // Try to save into ordinary smiles and find what cis-trans bonds were used
   NullOutput null_output;
   SmilesSaver saver_cistrans(null_output);
   saver_cistrans.ignore_hydrogens = true;
   saver_cistrans.saveMolecule(mol);
   // Then reset cis-trans infromation that is not saved into SMILES
   const Array<int>& parities = saver_cistrans.getSavedCisTransParities();
   for (i = mol.edgeBegin(); i < mol.edgeEnd(); i = mol.edgeNext(i))
   {
      if (mol.cis_trans.getParity(i) != 0 && parities[i] == 0)
         mol.cis_trans.setParity(i, 0);
   }

   MoleculeAutomorphismSearch of;

   of.detect_invalid_cistrans_bonds = find_invalid_stereo;
   of.detect_invalid_stereocenters = find_invalid_stereo;
   of.find_canonical_ordering = true;
   of.ignored_vertices = ignored.ptr();
   of.process(mol);
   of.getCanonicalNumbering(order);

   for (i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i))
      if (mol.cis_trans.getParity(i) != 0 && of.invalidCisTransBond(i))
         mol.cis_trans.setParity(i, 0);

   for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
      if (mol.stereocenters.getType(i) > MoleculeStereocenters::ATOM_ANY && of.invalidStereocenter(i))
         mol.stereocenters.remove(i);

   ranks.clear_resize(mol.vertexEnd());

   for (i = 0; i < order.size(); i++)
      ranks[order[i]] = i;

   vertex_ranks = ranks.ptr();

   _actual_atom_atom_mapping.clear_resize(mol.vertexCount());
   _actual_atom_atom_mapping.zerofill();

   for (int i = 0; i < order.size(); ++i) {
      int aam = mol.reaction_atom_mapping[order[i]];
      if (aam) {
         if (!_initial_to_actual.find(aam)) {
            _initial_to_actual.insert(aam, ++_aam_counter);
            _actual_atom_atom_mapping[order[i]] = _aam_counter;
         }
         else {
            _actual_atom_atom_mapping[order[i]] = _initial_to_actual.at(aam);
         }
      }
   }
   mol.reaction_atom_mapping.copy(_actual_atom_atom_mapping);

   SmilesSaver::saveMolecule(mol);
}