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);
   
}
Example #2
0
bool MoleculeAromatizer::aromatizeBonds (Molecule &mol, const AromaticityOptions &options)
{
   MoleculeAromatizer aromatizer(mol, options);

   aromatizer.precalculatePiLabels();
   aromatizer.aromatize();

   bool aromatic_bond_found = false;
   for (int e_idx = mol.edgeBegin(); e_idx < mol.edgeEnd(); e_idx = mol.edgeNext(e_idx))
      if (aromatizer.isBondAromatic(e_idx))
      {
         mol.setBondOrder(e_idx, BOND_AROMATIC, true);
         aromatic_bond_found = true;
      }

   // Aromatize RGroups
   int n_rgroups = mol.rgroups.getRGroupCount();
   for (int i = 1; i <= n_rgroups; i++)
   {
      PtrPool<BaseMolecule> &frags = mol.rgroups.getRGroup(i).fragments;

      for (int j = frags.begin(); j != frags.end(); j = frags.next(j))
      {
         Molecule &fragment = frags[j]->asMolecule();
         aromatic_bond_found |= MoleculeAromatizer::aromatizeBonds(fragment, options);
      }
   }

   return aromatic_bond_found;
}
bool MoleculeAutomorphismSearch::_hasStereo (Molecule &mol)
{
   for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i))
      if (mol.cis_trans.getParity(i) != 0)
         return true;
   if (mol.stereocenters.size() != 0)
      return true;
   return false;
}
Example #4
0
void IndigoInchi::saveMoleculeIntoInchi (Molecule &mol, Array<char> &inchi)
{
   inchi_Input input;
   QS_DEF(Array<inchi_Atom>, atoms);
   QS_DEF(Array<inchi_Stereo0D>, stereo);

   // Check if structure has aromatic bonds
   bool has_aromatic = false;
   for (int e = mol.edgeBegin(); e != mol.edgeEnd(); e = mol.edgeNext(e))
      if (mol.getBondOrder(e) == BOND_AROMATIC)
      {
         has_aromatic = true;
         break;
      }

   Molecule *target = &mol;
   Obj<Molecule> dearom;
   if (has_aromatic)
   {
      dearom.create();
      dearom->clone(mol, 0, 0);
      try
      {
         dearom->dearomatize();
      }
      catch (DearomatizationsGroups::Error &)
      {
      }
      target = dearom.get();
   }
   generateInchiInput(*target, input, atoms, stereo);

   inchi_Output output;
   
   int ret = GetINCHI(&input, &output);

   if (output.szMessage)
      warning.readString(output.szMessage, true);
   if (output.szLog)
      log.readString(output.szLog, true);
   if (output.szAuxInfo)
      auxInfo.readString(output.szAuxInfo, true);

   if (ret != inchi_Ret_OKAY && ret != inchi_Ret_WARNING)
   {
      // Construct error before dispoing inchi output to preserve error message
      IndigoError error("Indigo-InChI: InChI generation failed: %s. Code: %d.", output.szMessage, ret);
      FreeINCHI(&output);
      throw error;
   }

   inchi.readString(output.szInChI, true);

   FreeINCHI(&output);
}
Example #5
0
void MangoExact::_initQuery (Molecule &query)
{
   int i;
   MoleculeAromatizer::aromatizeBonds(query, AromaticityOptions::BASIC);

   if (_flags & MoleculeExactMatcher::CONDITION_STEREO)
   {
      for (i = query.edgeBegin(); i != query.edgeEnd(); i = query.edgeNext(i))
         if (query.getEdgeTopology(i) == TOPOLOGY_RING)
            query.cis_trans.setParity(i, 0);
   }
}
void MoleculeAutomorphismSearch::_markComplicatedStereocentersAsValid (Molecule &mol)
{
   // If there is more then 1 unknown stereocenter in the biconnected 
   // component then validity of such stereocenters cannot be found 
   // with current methods. For example C[C@H]1C[C@@H](C)C[C@H](C)C1 
   // can lead to CC1C[C@H](C)C[C@@H](C)C1 or CC1C[C@@H](C)C[C@H](C)C1, 
   // but canonical codes are different for such molecules.
   QS_DEF(Array<int>, single_bond_bridge_mark);
   single_bond_bridge_mark.resize(mol.edgeEnd());
   single_bond_bridge_mark.fill(1);

   SpanningTree sp_tree(mol, 0);
   sp_tree.markAllEdgesInCycles(single_bond_bridge_mark.ptr(), 0);
   for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i++)
      if (mol.getBondOrder(i) != BOND_SINGLE)
         single_bond_bridge_mark[i] = 0;

   Filter edge_filter(single_bond_bridge_mark.ptr(), Filter::NEQ, 1);
   GraphDecomposer decomposer(mol);
   decomposer.decompose(0, &edge_filter);

   const Array<int> &decomposition = decomposer.getDecomposition();

   QS_DEF(Array<int>, undef_stereo_in_component);
   undef_stereo_in_component.clear();

   for (int v = mol.vertexBegin(); v != mol.vertexEnd(); v = mol.vertexNext(v))
   {
      int comp = decomposition[v];

      if (comp < 0)
         continue;
      while (undef_stereo_in_component.size() <= comp)
         undef_stereo_in_component.push(0);

      if (_stereocenter_state[v] == _UNDEF)
         undef_stereo_in_component[comp]++;
   }

   // Mark stereocenters as valid if there are more then 1 
   // undefined stereocenter in the component
   for (int v = mol.vertexBegin(); v != mol.vertexEnd(); v = mol.vertexNext(v))
   {
      int comp = decomposition[v];

      if (comp < 0)
         continue;
      if (_stereocenter_state[v] == _UNDEF && undef_stereo_in_component[comp] > 1)
         _stereocenter_state[v] = _VALID;
   }
}
void MoleculePiSystemsMatcher::_calcConnectivity (Molecule &mol, Array<int> &conn)
{
   conn.clear_resize(mol.vertexEnd());
   conn.zerofill();
   for (int e = mol.edgeBegin(); e != mol.edgeEnd(); e = mol.edgeNext(e))
   {
      int bond_order = mol.getBondOrder(e);

      const Edge &edge = mol.getEdge(e);
      conn[edge.beg] += bond_order;
      conn[edge.end] += bond_order;
   }
   for (int v = mol.vertexBegin(); v != mol.vertexEnd(); v = mol.vertexNext(v))
      if (!mol.isPseudoAtom(v) && !mol.isRSite(v))
         conn[v] += mol.getImplicitH(v);
}
void MoleculeAutomorphismSearch::_getFirstApproximation (Molecule &mol)
{
   _stereocenter_state.clear_resize(mol.vertexEnd());
   _cistrans_bond_state.clear_resize(mol.edgeEnd());

   const MoleculeStereocenters &stereocenters = mol.stereocenters;
   for (int i = 0; i < _stereocenter_state.size(); i++)
      _stereocenter_state[i] = _NO_STEREO;
   for (int i = stereocenters.begin(); i != stereocenters.end(); i = stereocenters.next(i))
   {
      int atom_index = stereocenters.getAtomIndex(i);
      _stereocenter_state[atom_index] = _UNDEF;
   }

   for (int i = 0; i < _cistrans_bond_state.size(); i++)
      _cistrans_bond_state[i] = _NO_STEREO;
   for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i))
      if (mol.cis_trans.getParity(i))
         _cistrans_bond_state[i] = _UNDEF;

   _cistrans_stereo_bond_parity.clear_resize(mol.edgeEnd());
   _cistrans_stereo_bond_parity.zerofill();

   _treat_undef_as = _INVALID;
   _target_stereocenter = -1;
   _target_bond = -1;

   // Approximation orbits cannot be used on this step because 
   // of existance of check_automorphism method. But order from 
   // first refinment can be used here.
   _approximation_orbits.fffill();

   profTimerStart(t0, "mol_auto.first_search");
   AutomorphismSearch::process(mol);
   profTimerStop(t0);

   getCanonicallyOrderedOrbits(_approximation_orbits);

   _findCisTransStereoBondParirties(mol);
}
bool MoleculeAutomorphismSearch::_findInvalidStereoCisTrans (Molecule &mol)
{
   _treat_undef_as = _VALID;

   QS_DEF(Array<int>, invalid_stereo);
   invalid_stereo.clear();

   bool invalid_found = false;

   for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i))
   {
      if (_cistrans_bond_state[i] != _UNDEF || mol.cis_trans.getParity(i) == 0)
         continue;

      if (ignored_vertices != 0)
      {
         const Edge &edge = mol.getEdge(i);
         if (ignored_vertices[edge.beg] || ignored_vertices[edge.end])
            continue;
      }

      _cistrans_bond_state[i] = _INVALID;

      if (_checkCisTransInvalid(mol, i))
         // Stereobond is invalid
         invalid_stereo.push(i);

      _cistrans_bond_state[i] = _UNDEF;
   }

   // Mark invalid stereocenters
   for (int i = 0; i < invalid_stereo.size(); i++)
   {
      int bond_index = invalid_stereo[i];
      _cistrans_bond_state[bond_index] = _INVALID;
      invalid_found = true;
   }

   return invalid_found;
}
void MoleculeAutomorphismSearch::_findCisTransStereoBondParirties (Molecule &mol)
{
   const MoleculeStereocenters &stereocenters = mol.stereocenters;

   // Mark edges that connects two stereocenters and that common parity can be detected
   for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i))
   {
      const Edge &edge = mol.getEdge(i);
      if (!stereocenters.exists(edge.beg) || !stereocenters.exists(edge.end))
         continue;
      if (stereocenters.getGroup(edge.beg) != stereocenters.getGroup(edge.end))
         continue;
      if (stereocenters.getType(edge.beg) != stereocenters.getType(edge.end))
         continue;

      // Both stereocenters exists and groups are the same

      int orb_beg = _approximation_orbits[edge.beg];
      int orb_end = _approximation_orbits[edge.end];

      _approximation_orbits[edge.beg] = -2; // Some value different from -1 and other orbits
      _approximation_orbits[edge.end] = -2;

      int parity_beg, parity_end;
      if (_validStereocenterByAtom(edge.beg, _approximation_orbits, &parity_beg) == _VALID &&
         _validStereocenterByAtom(edge.end, _approximation_orbits, &parity_end) == _VALID)
      {
         // 1 - means that both stereocenters have the same parity
         _cistrans_stereo_bond_parity[i] = -parity_beg * parity_end;
      }

      // Restore orbits
      _approximation_orbits[edge.beg] = orb_beg;
      _approximation_orbits[edge.end] = orb_end;
   }
}
Example #11
0
void IndigoInchi::generateInchiInput (Molecule &mol, inchi_Input &input, 
   Array<inchi_Atom> &atoms, Array<inchi_Stereo0D> &stereo)
{
   QS_DEF(Array<int>, mapping);
   mapping.clear_resize(mol.vertexEnd());
   mapping.fffill();
   int index = 0;
   for (int v = mol.vertexBegin(); v != mol.vertexEnd(); v = mol.vertexNext(v))
      mapping[v] = index++;
   atoms.clear_resize(index);
   atoms.zerofill();

   stereo.clear();
   for (int v = mol.vertexBegin(); v != mol.vertexEnd(); v = mol.vertexNext(v))
   {
      inchi_Atom &atom = atoms[mapping[v]];
      
      int atom_number = mol.getAtomNumber(v);
      if (atom_number == ELEM_PSEUDO)
         throw IndigoError("Molecule with pseudoatom (%s) cannot be converted into InChI", mol.getPseudoAtom(v));
      if (atom_number == ELEM_RSITE)
         throw IndigoError("Molecule with RGroups cannot be converted into InChI");
      strncpy(atom.elname, Element::toString(atom_number), ATOM_EL_LEN);

      Vec3f &c = mol.getAtomXyz(v);
      atom.x = c.x;
      atom.y = c.y;
      atom.z = c.z;
                              
      // connectivity
      const Vertex &vtx = mol.getVertex(v);
      int nei_idx = 0;
      for (int nei = vtx.neiBegin(); nei != vtx.neiEnd(); nei = vtx.neiNext(nei))
      {
         int v_nei = vtx.neiVertex(nei);
         atom.neighbor[nei_idx] = mapping[v_nei];
         int edge_idx = vtx.neiEdge(nei);
         atom.bond_type[nei_idx] = getInchiBondType(mol.getBondOrder(edge_idx));

         int bond_stereo = INCHI_BOND_STEREO_NONE;
         if (mol.cis_trans.isIgnored(edge_idx))
            bond_stereo = INCHI_BOND_STEREO_DOUBLE_EITHER;
         else
         {
            int dir = mol.getBondDirection2(v, v_nei);
            if (mol.getBondDirection2(v, v_nei) == BOND_EITHER)
               bond_stereo = INCHI_BOND_STEREO_SINGLE_1EITHER;
            else if (mol.getBondDirection2(v_nei, v) == BOND_EITHER)
               bond_stereo = INCHI_BOND_STEREO_SINGLE_2EITHER;
         }
         atom.bond_stereo[nei_idx] = bond_stereo;
         nei_idx++;
      }
      atom.num_bonds = vtx.degree();

      // Other properties
      atom.isotopic_mass = mol.getAtomIsotope(v);
      atom.radical = mol.getAtomRadical(v);
      atom.charge = mol.getAtomCharge(v);

      // Hydrogens
      int hcount = -1;
      if (Molecule::shouldWriteHCount(mol, v) || mol.isExplicitValenceSet(v) || mol.isImplicitHSet(v))
      {
         if (mol.getAtomAromaticity(v) == ATOM_AROMATIC &&
            atom_number == ELEM_C && atom.charge == 0 && atom.radical == 0)
         {
            // Do not set number of implicit hydrogens here as InChI throws an exception on
            // the molecule B1=CB=c2cc3B=CC=c3cc12
            ;
         }
         else
            // set -1 to tell InChI add implicit hydrogens automatically
            hcount = mol.getImplicitH_NoThrow(v, -1); 
      }
      atom.num_iso_H[0] = hcount;
   }
  
   // Process cis-trans bonds
   for (int e = mol.edgeBegin(); e != mol.edgeEnd(); e = mol.edgeNext(e))
   {
      if (mol.cis_trans.getParity(e) == 0)
         continue;

      int subst[4];
      mol.cis_trans.getSubstituents_All(e, subst);

      const Edge &edge = mol.getEdge(e);

      inchi_Stereo0D &st = stereo.push();

      // Write it as
      // #0 - #1 = #2 - #3
      st.neighbor[0] = mapping[subst[0]];
      st.neighbor[1] = mapping[edge.beg];
      st.neighbor[2] = mapping[edge.end];
      st.neighbor[3] = mapping[subst[2]];

      if (mol.cis_trans.getParity(e) == MoleculeCisTrans::CIS)
         st.parity = INCHI_PARITY_ODD;
      else
         st.parity = INCHI_PARITY_EVEN;

      st.central_atom = NO_ATOM;
      st.type = INCHI_StereoType_DoubleBond;
   }

   // Process tetrahedral stereocenters
   for (int i = mol.stereocenters.begin(); i != mol.stereocenters.end(); i = mol.stereocenters.next(i))
   {
      int v = mol.stereocenters.getAtomIndex(i);

      int type, group, pyramid[4];
      mol.stereocenters.get(v, type, group, pyramid);
      if (type == MoleculeStereocenters::ATOM_ANY)
         continue;

      for (int i = 0; i < 4; i++)
         if (pyramid[i] != -1)
            pyramid[i] = mapping[pyramid[i]];

      inchi_Stereo0D &st = stereo.push();

      /*
         4 neighbors

                  X                    neighbor[4] : {#W, #X, #Y, #Z}
                  |                    central_atom: #A
               W--A--Y                 type        : INCHI_StereoType_Tetrahedral
                  |
                  Z
         parity: if (X,Y,Z) are clockwize when seen from W then parity is 'e' otherwise 'o'
         Example (see AXYZW above): if W is above the plane XYZ then parity = 'e'

         3 neighbors

                    Y          Y       neighbor[4] : {#A, #X, #Y, #Z}
                   /          /        central_atom: #A
               X--A  (e.g. O=S   )     type        : INCHI_StereoType_Tetrahedral
                   \          \
                    Z          Z
      */
      int offset = 0;
      if (pyramid[3] == -1)
         offset = 1;

      st.neighbor[offset] = mapping[pyramid[0]];
      st.neighbor[offset + 1] = mapping[pyramid[1]];
      st.neighbor[offset + 2] = mapping[pyramid[2]];
      if (offset == 0)
         st.neighbor[3] = mapping[pyramid[3]];
      else
         st.neighbor[0] = mapping[v];

      st.parity = INCHI_PARITY_ODD;
      if (offset != 0)
         st.parity = INCHI_PARITY_ODD;
      else
         st.parity = INCHI_PARITY_EVEN;
      st.central_atom = mapping[v];
      st.type = INCHI_StereoType_Tetrahedral;
   }

   input.atom = atoms.ptr();
   input.num_atoms = atoms.size();
   input.stereo0D = stereo.ptr();
   input.num_stereo0D = stereo.size();
   input.szOptions = options.ptr();
}
void MoleculeAutomorphismSearch::process (Molecule &mol)
{
   _initialize(mol);

   if (detect_invalid_stereocenters || detect_invalid_cistrans_bonds)
   {
      // Mark stereocenters that are valid
      _markValidOrInvalidStereo(true, _approximation_orbits, NULL);
      _markValidOrInvalidStereo(false, _approximation_orbits, NULL);

      // Temposrary solution: mark unknown stereocenters as valid if 
      // number of them is more then 1 in each component
      _markComplicatedStereocentersAsValid(mol);

      // Find invalid stereocenters and bonds iteratively
      // For each component
      const int *ignored_vertices_saved = ignored_vertices;

      GraphDecomposer decomposer(mol);
      int ncomp = decomposer.decompose();
      QS_DEF(Array<int>, ignored_vertices_arr);
      ignored_vertices_arr.resize(mol.vertexEnd());
      ignored_vertices = ignored_vertices_arr.ptr();

      for (int comp = 0; comp < ncomp; comp++)
      {
         // Copy existing ignores vertices
         if (ignored_vertices_saved != 0)
            ignored_vertices_arr.copy(ignored_vertices_saved, mol.vertexEnd());
         else
            ignored_vertices_arr.zerofill();

         for (int i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
         {
            if (decomposer.getComponent(i) != comp)
               ignored_vertices_arr[i] = 1;
         }

         while (_findInvalidStereo(mol))
            ;
      }

      ignored_vertices = ignored_vertices_saved;
   }

   // Mark all other stereocenters and stereobonds as valid
   const MoleculeStereocenters &stereocenters = mol.stereocenters;
   for (int i = stereocenters.begin(); i != stereocenters.end(); i = stereocenters.next(i))
   {
      int atom_index = stereocenters.getAtomIndex(i);
      if (_stereocenter_state[atom_index] == _UNDEF)
         _stereocenter_state[atom_index] = _VALID;
   }
   for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i))
      if (_cistrans_bond_state[i] == _UNDEF && mol.cis_trans.getParity(i) != 0)
         _cistrans_bond_state[i] = _VALID;

   // Find final orbits and canonical ordering with found 
   // valid and invalid stereocenters and bonds
   _target_stereocenter = -1;
   _target_bond = -1;
   _fixed_atom = -1;

   // Find possible cis-trans bonds
   _findAllPossibleCisTrans(mol);

   if (find_canonical_ordering)
   {
      profTimerStart(t0, "mol_auto.final_search");
      AutomorphismSearch::process(mol);
      profTimerStop(t0);
   }
}
TautomerSuperStructure::TautomerSuperStructure (Molecule &mol) :
CP_INIT,
TL_CP_GET(_atomsEmitBond),
TL_CP_GET(_atomsAcceptBond),
TL_CP_GET(_isBondAttachedArray),
TL_CP_GET(_mapping),
TL_CP_GET(_inv_mapping),
TL_CP_GET(_edge_mapping),
TL_CP_GET(_total_h)
{
   int i;

   _inside_ctor = true;

   clone(mol, &_inv_mapping, &_mapping);

   _edge_mapping.clear_resize(edgeEnd());
   _edge_mapping.fffill();

   for (i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i))
   {
      const Edge &edge = mol.getEdge(i);

      _edge_mapping[findEdgeIndex(_inv_mapping[edge.beg],
              _inv_mapping[edge.end])] = i;
   }

   // Collect atom properties
   _collectAtomProperties();

   // Detect distances from _atomsEmitBond elements to _atomsAcceptBond elements
   QS_DEF(Array<int>, distancesMatrix);
   distancesMatrix.resize(_atomsEmitBond.size() * _atomsAcceptBond.size());
   for (int i = 0; i < _atomsEmitBond.size(); i++)
   {
      int *result = distancesMatrix.ptr() + _atomsAcceptBond.size() * i;
      _findMinDistance(_atomsEmitBond[i], 6, _atomsAcceptBond, result);
   }


   QS_DEF(Array<int>, attachedBonds);
   attachedBonds.clear();
   for (int i = 0; i < _atomsEmitBond.size(); i++)
      for (int j = 0; j < _atomsAcceptBond.size(); j++)
      {
         int v1 = _atomsEmitBond[i];
         int v2 = _atomsAcceptBond[j];
         if (findEdgeIndex(v1, v2) != -1)
            continue;
         // Check new loop size: 5 or 6
         int size = distancesMatrix[_atomsAcceptBond.size() * i + j];
         if (size != 4 && size != 5)
            continue;

         attachedBonds.push(addEdge(v1, v2));
      }

   _isBondAttachedArray.resize(edgeEnd());
   _isBondAttachedArray.zerofill();
   for (int i = 0; i < attachedBonds.size(); i++)
      _isBondAttachedArray[attachedBonds[i]] = true;

   _inside_ctor = false;
}

TautomerSuperStructure::~TautomerSuperStructure ()
{
}


void TautomerSuperStructure::clear ()
{
   if (_inside_ctor)
      Molecule::clear();
   else
      throw Exception("clear(): not supported");
}

int TautomerSuperStructure::getBondOrder (int idx)
{
   if (!_inside_ctor && _isBondAttachedArray[idx])
      return -1;
   return Molecule::getBondOrder(idx);
}

int TautomerSuperStructure::getBondTopology (int idx)
{
   if (!_inside_ctor &&_isBondAttachedArray[idx])
      return -1;
   return Molecule::getBondTopology(idx);
}

bool TautomerSuperStructure::possibleBondOrder (int idx, int order)
{
   if (!_inside_ctor &&_isBondAttachedArray[idx])
      return order == 0 || order == BOND_SINGLE;

   return Molecule::possibleBondOrder(idx, order);
}

int TautomerSuperStructure::getSubgraphType (const Array<int> &vertices, const Array<int> &edges)
{
   // For any atoms number of attached bonds must be 0 or 1

   QS_DEF(Array<int>, per_vertex_attached_bonds);

   per_vertex_attached_bonds.clear_resize(vertexEnd());
   per_vertex_attached_bonds.zerofill();

   int attached_bonds = 0;
   for (int i = 0; i < edges.size(); i++)
   {
      int edge_index = edges[i];

      if (!_isBondAttachedArray[edge_index])
         continue;

      const Edge &edge = getEdge(edge_index);
      per_vertex_attached_bonds[edge.beg]++;
      per_vertex_attached_bonds[edge.end]++;
      if (per_vertex_attached_bonds[edge.beg] > 1 || per_vertex_attached_bonds[edge.end] > 1)
         return NONE;
      attached_bonds++;
   }

   if (attached_bonds == 0)
      return ORIGINAL;
   return TAUTOMER;
}
Example #14
0
void CrfSaver::_writeMolecule (Molecule &molecule)
{
   Obj<CmfSaver> saver;
   int i;

   if (_encoder.get() != 0)
      saver.create(_encoder.ref());
   else
      saver.create(_output);

   QS_DEF(Array<int>, atom_flags);
   QS_DEF(Array<int>, bond_flags);

   if (_atom_stereo_flags != 0)
   {
      atom_flags.clear_resize(molecule.vertexEnd());
      atom_flags.zerofill();

      for (i = molecule.vertexBegin(); i != molecule.vertexEnd(); i = molecule.vertexNext(i))
         if (_atom_stereo_flags[i] == STEREO_RETAINS)
            atom_flags[i] = 1;
         else if (_atom_stereo_flags[i] == STEREO_INVERTS)
            atom_flags[i] = 2;
      saver->atom_flags = atom_flags.ptr();
   }

   if (_bond_rc_flags != 0)
   {
      bond_flags.clear_resize(molecule.edgeEnd());
      bond_flags.zerofill();

      for (i = molecule.edgeBegin(); i != molecule.edgeEnd(); i = molecule.edgeNext(i))
      {
         if (_bond_rc_flags[i] & RC_UNCHANGED)
            bond_flags[i] |= 1;
         if (_bond_rc_flags[i] & RC_MADE_OR_BROKEN)
            bond_flags[i] |= 2;
         if (_bond_rc_flags[i] & RC_ORDER_CHANGED)
            bond_flags[i] |= 4;
      }
      saver->bond_flags = bond_flags.ptr();
   }

   saver->save_bond_dirs = save_bond_dirs;
   saver->save_highlighting = save_highlighting;
   saver->save_mapping = save_mapping;

   saver->saveMolecule(molecule);

   if (_aam != 0)
      _writeAam(_aam, saver->getAtomSequence());

   if (xyz_output != 0)
   {
      if (xyz_output == &_output && _encoder.get() != 0)
         _encoder->finish();

      saver->saveXyz(*xyz_output);

      if (xyz_output == &_output && _encoder.get() != 0)
         _encoder->start();
   }
}
Example #15
0
void convertMolfile (char *path, char *filename, FileOutput &cpp_file)
{
   FileScanner molfile("%s\\%s", path, filename);
   MolfileLoader mf_loader(molfile);
   Molecule mol;
   QS_DEF(Array<int>, edges);

   printf("%s\n", filename);

   mf_loader.loadMolecule(mol, true);

   BiconnectedDecomposer bd(mol); 

   if (bd.decompose() != 1)
   {
      printf("Error: %s is not biconnected\n", filename);
      return;
   }

   int i, j;

   edges.clear_reserve(mol.edgeCount());

   for (i = mol.edgeBegin() ; i < mol.edgeEnd(); i = mol.edgeNext(i))
      edges.push(i);

   edges.qsort(edge_cmp, &mol);

   const Edge &edge = mol.getEdge(edges[edges.size() / 2]);

   Vec3f v1 = mol.getAtomPos(edge.beg);
   Vec3f v2 = mol.getAtomPos(edge.end);

   v1.z = 0.f;
   v2.z = 0.f;

   float scale = Vec3f::dist(v1, v2);

   if (scale < 0.0001f)
   {
      printf("Error: %s has zero bond\n", filename);
      return;
   }

   scale = 1.f / scale;

   int first_idx = mol.vertexBegin();
   Vec3f pos = mol.getAtomPos(first_idx);

   for (i = mol.vertexNext(first_idx); i < mol.vertexEnd(); i = mol.vertexNext(i))
   {
      if (mol.getAtomPos(i).y < pos.y)
      {
         pos = mol.getAtomPos(i);
         first_idx = i;
      }
   }


   for (i = mol.vertexBegin() ; i < mol.vertexEnd(); i = mol.vertexNext(i))
   {
      mol.getAtom2(i).pos.sub(pos);
      mol.getAtom2(i).pos.scale(scale);
   }

   char buf[1024];

   sprintf_s(buf, "BEGIN_PATTERN(\"%s\")", filename);
   cpp_file.writeStringCR(buf);   

   for (i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i))
   {
      sprintf_s(buf, "   ADD_ATOM(%d, %ff, %ff)", i, mol.getAtomPos(i).x, mol.getAtomPos(i).y);
      cpp_file.writeStringCR(buf);   
   }

   for (i = mol.edgeBegin(); i < mol.edgeEnd(); i = mol.edgeNext(i))
   {
      const Edge &edge = mol.getEdge(i);
      int type = mol.getBond(i).type;
      int qtype = mol.getQueryBond(i).type;

      sprintf_s(buf, "   ADD_BOND(%d, %d, %d)", edge.beg, edge.end, qtype != 0 ? qtype : type);
      cpp_file.writeStringCR(buf);   
   }

   Vec2f v, inter;
   Vec2f pos_i;
   int idx = mol.vertexCount();

   i = first_idx;

   float max_angle, cur_angle;
   float i_angle = 0;
   int next_nei = 0;
   int point_idx = 0;

   pos_i.set(mol.getAtomPos(i).x, mol.getAtomPos(i).y);

   while (true)
   {
      const Vertex &vert = mol.getVertex(i);

      if (i != first_idx)
      {
         v.set(pos_i.x, pos_i.y);
         pos_i.set(mol.getAtomPos(i).x, mol.getAtomPos(i).y);
         v.sub(pos_i);

         i_angle = v.tiltAngle2();
      } else if (point_idx > 0)
         break;

      sprintf_s(buf, "   OUTLINE_POINT(%d, %ff, %ff)", point_idx++, pos_i.x, pos_i.y);
      cpp_file.writeStringCR(buf);

      max_angle = 0.f;

      for (j = vert.neiBegin(); j < vert.neiEnd(); j = vert.neiNext(j))
      {
         const Vec3f &pos_nei = mol.getAtomPos(vert.neiVertex(j));

         v.set(pos_nei.x - pos_i.x, pos_nei.y - pos_i.y);

         cur_angle = v.tiltAngle2() - i_angle;

         if (cur_angle < 0.f)
            cur_angle += 2 * PI;

         if (max_angle < cur_angle)
         {
            max_angle = cur_angle;
            next_nei = j;
         }
      }
      
      i = vert.neiVertex(next_nei);

      float dist, min_dist = 0.f;
      int int_edge;
      Vec2f cur_v1 = pos_i;
      Vec2f cur_v2(mol.getAtomPos(i).x, mol.getAtomPos(i).y);

      while (min_dist < 10000.f)
      {
         min_dist = 10001.f;

         for (j = mol.edgeBegin(); j < mol.edgeEnd(); j = mol.edgeNext(j))
         {
            const Edge &edge = mol.getEdge(j);
            Vec2f cur_v3(mol.getAtomPos(edge.beg).x, mol.getAtomPos(edge.beg).y);
            Vec2f cur_v4(mol.getAtomPos(edge.end).x, mol.getAtomPos(edge.end).y);

            if (Vec2f::intersection(cur_v1, cur_v2, cur_v3, cur_v4, v))
               if ((dist = Vec2f::dist(cur_v1, v)) < min_dist)
               {
                  inter = v;
                  min_dist = dist;
                  int_edge = j;
               }
         }

         if (min_dist < 10000.f)
         {
            sprintf_s(buf, "   OUTLINE_POINT(%d, %ff, %ff)", point_idx++, v.x, v.y);
            cpp_file.writeStringCR(buf);   

            const Edge &edge = mol.getEdge(int_edge);
            Vec2f cur_v3(mol.getAtomPos(edge.beg).x, mol.getAtomPos(edge.beg).y);
            Vec2f cur_v4(mol.getAtomPos(edge.end).x, mol.getAtomPos(edge.end).y);

            Vec2f cur_v1v;
            Vec2f cur_v3v;
            Vec2f cur_v4v;

            cur_v1v.diff(cur_v1, inter);
            cur_v3v.diff(cur_v3, inter);
            cur_v4v.diff(cur_v4, inter);

            float angle1 = cur_v1v.tiltAngle2();
            float angle3 = cur_v3v.tiltAngle2() - angle1;
            float angle4 = cur_v4v.tiltAngle2() - angle1;

            if (angle3 < 0)
               angle3 += 2 * PI;
            if (angle4 < 0)
               angle4 += 2 * PI;

            cur_v1 = inter;

            if (angle3 > angle4)
            {
               cur_v2 = cur_v3;
               i = edge.beg;
            } else
            {
               cur_v2 = cur_v4;
               i = edge.end;
            }
         }
      }
   }

   cpp_file.writeStringCR("END_PATTERN()");   
}