int MoleculeSubstructureMatcher::_compare_frequency_asc (BaseMolecule &mol, int i1, int i2)
{
   static int labels_by_freq[] =
     {ELEM_C, ELEM_H, ELEM_O, ELEM_N, ELEM_P, ELEM_F,
      ELEM_S, ELEM_Si, ELEM_Cl, ELEM_Br, ELEM_I, ELEM_At};
   
   int label1 = mol.getAtomNumber(i1);
   int label2 = mol.getAtomNumber(i2);
   int idx1, idx2;

   for (idx1 = 0; idx1 < (int)NELEM(labels_by_freq); idx1++)
      if (label1 == labels_by_freq[idx1])
         break;
   for (idx2 = 0; idx2 < (int)NELEM(labels_by_freq); idx2++)
      if (label2 == labels_by_freq[idx2])
         break;

   return idx2 - idx1;
}
Esempio n. 2
0
void MoleculeCisTrans::_fillAtomExplicitHydrogens (BaseMolecule &mol, int atom_idx, int subst[2])
{
   const Vertex &vertex = mol.getVertex(atom_idx);

   for (int i = vertex.neiBegin(); i != vertex.neiEnd(); i = vertex.neiNext(i))
   {
      int nei = vertex.neiVertex(i);
      // check [H]\N=C\C
      if (_pureH(mol, nei))
      {
         if (subst[0] != nei)
            subst[1] = nei;
         else if (subst[1] != nei)
            subst[0] = nei;
         else
            throw Error("internal error in _fillAtomExplicitHydrogens");
      }
   }
}
Esempio n. 3
0
void Metalayout::getBoundRect (Vec2f& min, Vec2f& max, BaseMolecule& mol)
{
   if (mol.vertexCount() == 0)
   {
      min.zero();
      max.zero();
      return;
   }
   const Vec3f& v0 = mol.getAtomXyz(mol.vertexBegin());
   Vec2f::projectZ(min, v0);
   Vec2f::projectZ(max, v0);
   Vec2f v2;
   for (int i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i))
   {
      Vec2f::projectZ(v2, mol.getAtomXyz(i));
      min.min(v2);
      max.max(v2);
   }
}
MoleculeSubstructureMatcher::MoleculeSubstructureMatcher (BaseMolecule &target) :
_target(target),
TL_CP_GET(_3d_constrained_atoms),
TL_CP_GET(_unfolded_target_h),
TL_CP_GET(_used_target_h)
{
   vertex_equivalence_handler = NULL;
   use_aromaticity_matcher = true;
   use_pi_systems_matcher = false;
   _query = 0;
   match_3d = 0;
   rms_threshold = 0;

   highlight = false;
   find_all_embeddings = false;
   find_unique_embeddings = false;
   find_unique_by_edges = false;
   save_for_iteration = false;
   disable_folding_query_h = false;
   
   not_ignore_first_atom = false;

   cb_embedding = 0;
   cb_embedding_context = 0;

   fmcache = 0;

   disable_unfolding_implicit_h = false;
   restore_unfolded_h = true;
   _h_unfold = false;

   _query_nei_counters = 0;
   _target_nei_counters = 0;
   
   _used_target_h.clear_resize(target.vertexEnd());

   // won't ignore target hydrogens because query can contain
   // 3d features, hydrogen isotopes, etc.
}
LayeredMolecules::LayeredMolecules(BaseMolecule& molecule)
   :_layersAromatized(0)
{
   _proto.clone(molecule.asMolecule(), 0, 0);
   _proto.dearomatize(AromaticityOptions());

   cloneGraph(_proto, 0);

   for (auto e_idx : _proto.edges())
   {
      for(auto i = 0; i < BOND_TYPES_NUMBER; ++i)
      {
         _bond_masks[i].push();
         _bond_masks[i].top().resize(1);
      }

      _bond_masks[BOND_ZERO].top().reset(0);
      _bond_masks[BOND_SINGLE].top().reset(0);
      _bond_masks[BOND_DOUBLE].top().reset(0);
      _bond_masks[BOND_TRIPLE].top().reset(0);
      _bond_masks[BOND_AROMATIC].top().reset(0);
      _bond_masks[_proto.getBondOrder(e_idx)].top().set(0);
   }

   _mobilePositions.expandFill(_proto.vertexCount(), false);
   _mobilePositionsOccupied.expand(_proto.vertexCount());

   layers = 1;

   unsigned node = _trie.getRoot();
   for (auto i : _proto.edges())
   {
      bool stub;
      node = _trie.add(node, _proto.getBondOrder(i), stub);
   }
   _hashs.push(node);
}
Esempio n. 6
0
void Metalayout::adjustMol (BaseMolecule& mol, const Vec2f& min, const Vec2f& pos)
{
   float scaleFactor = getScaleFactor();

   // Compute center points for the data sgroups
   QS_DEF(Array<Vec2f>, data_centers);
   data_centers.resize(mol.data_sgroups.end());
   for (int i = mol.data_sgroups.begin(); i < mol.data_sgroups.end(); i = mol.data_sgroups.next(i))
   {
      BaseMolecule::DataSGroup &group = mol.data_sgroups[i];
      if (!group.relative)
         mol.getSGroupAtomsCenterPoint(group, data_centers[i]);
   }

   for (int i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i))
   {
      Vec2f v;
      Vec2f::projectZ(v, mol.getAtomXyz(i));
      v.sub(min);
      v.scale(scaleFactor);
      v.add(pos);
      v.y = -v.y;
      mol.setAtomXyz(i, v.x, v.y, 0);
   }  

   // Adjust data-sgroup label positions with absolute coordinates
   for (int i = mol.data_sgroups.begin(); i < mol.data_sgroups.end(); i = mol.data_sgroups.next(i))
   {
      BaseMolecule::DataSGroup &group = mol.data_sgroups[i];
      if (!group.relative)
      {
         Vec2f new_center;
         mol.getSGroupAtomsCenterPoint(group, new_center);
         group.display_pos.add(new_center);
         group.display_pos.sub(data_centers[i]);
      }
   }
}
Esempio n. 7
0
bool MoleculeCisTrans::_sameline (BaseMolecule &molecule, int i_beg, int i_end, int i_nei_beg)
{
   return sameline(molecule.getAtomXyz(i_beg), molecule.getAtomXyz(i_end),
                   molecule.getAtomXyz(i_nei_beg));
}
Esempio n. 8
0
float Metalayout::getTotalMoleculeClosestDist (BaseMolecule& mol)
{
   QS_DEF(Array<float>, dst);
   float sum = 0;

   dst.clear_resize(mol.vertexEnd());
   for (int i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i))
      dst[i] = -1;

   for (int i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i))
      for (int j = mol.vertexNext(i); j < mol.vertexEnd(); j = mol.vertexNext(j))
      {
         Vec2f u, v;
         Vec2f::projectZ(u, mol.getAtomXyz(i));
         Vec2f::projectZ(v, mol.getAtomXyz(j));
         float d = Vec2f::dist(u, v);
         if (dst[i] < 0 || dst[i] > d)
            dst[i] = d;
         if (dst[j] < 0 || dst[j] > d)
            dst[j] = d;
      }           
      for (int i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i))
         sum += dst[i];
      return sum;
}
Esempio n. 9
0
void MoleculeCisTrans::_fillExplicitHydrogens (BaseMolecule &mol, int bond_idx, int subst[4])
{
   _fillAtomExplicitHydrogens(mol, mol.getEdge(bond_idx).beg, subst);
   _fillAtomExplicitHydrogens(mol, mol.getEdge(bond_idx).end, subst + 2);
}
Esempio n. 10
0
bool MoleculeCisTrans::sortSubstituents (BaseMolecule &mol, int *substituents, bool *parity_changed)
{
   bool e0 = substituents[0] < 0;
   bool e1 = substituents[1] < 0;
   bool e2 = substituents[2] < 0;
   bool e3 = substituents[3] < 0;

   if (e0 && e1)
      return false;
   if (e2 && e3)
      return false;

   bool h0 = !e0 && _pureH(mol, substituents[0]);
   bool h1 = !e1 && _pureH(mol, substituents[1]);
   bool h2 = !e2 && _pureH(mol, substituents[2]);
   bool h3 = !e3 && _pureH(mol, substituents[3]);
   // Query molecules [H]/C=C/C and [H]\C=C/C are different
   // But normal molecules are the same.
   if (!mol.isQueryMolecule())
   {
      // Handle [H]/N=C\C and [H]/N=C/C
      if (!_commonHasLonePair(mol, substituents[0], substituents[1]))
      {
         h0 |= e0;
         h1 |= e1;
      }
      if (!_commonHasLonePair(mol, substituents[2], substituents[3]))
      {
         h2 |= e2;
         h3 |= e3;
      }
   }

   if (h0 && h1)
      return false;
   if (h2 && h3)
      return false;

   int tmp;

   // If hydrogens are explicit then keep them
   // And do not place explicit hydrogens to the end, because all static methods
   // should be converted into non-static with checking whether atom is hydrogen 
   // or not.
   // For example, molecule [H]\C(O)=C/C can get invalid parity because static 
   // functions getMappingParitySign, applyMapping doesn't know about 
   bool swapped = false;
   if (!e1)
      if (e0 || substituents[0] > substituents[1])
      {
         __swap(substituents[0], substituents[1], tmp);
         swapped = !swapped;
      }

   if (!e3)
      if (e2 || substituents[2] > substituents[3])
      {
         __swap(substituents[2], substituents[3], tmp);
         swapped = !swapped;
      }

   if (parity_changed != 0)
      *parity_changed = swapped;

   return true;
}
Esempio n. 11
0
bool MoleculeCisTrans::isGeomStereoBond (BaseMolecule &mol, int bond_idx,
                                         int *substituents, bool have_xyz)
{
   int substituents_local[4];

   if (substituents == 0)
      substituents = substituents_local;

   // it must be [C,N,Si,Ge]=[C,N,Si,Ge] bond
   if (!mol.possibleBondOrder(bond_idx, BOND_DOUBLE))
      return false;

   const Edge &edge = mol.getEdge(bond_idx);
   int beg_idx = edge.beg;
   int end_idx = edge.end;

   if (!mol.possibleAtomNumber(beg_idx, ELEM_C) &&
       !mol.possibleAtomNumber(beg_idx, ELEM_N) &&
       !mol.possibleAtomNumber(beg_idx, ELEM_Si) &&
       !mol.possibleAtomNumber(beg_idx, ELEM_Ge))
      return false;
   if (!mol.possibleAtomNumber(end_idx, ELEM_C) &&
       !mol.possibleAtomNumber(end_idx, ELEM_N) &&
       !mol.possibleAtomNumber(end_idx, ELEM_Si) &&
       !mol.possibleAtomNumber(end_idx, ELEM_Ge))
      return false;

   // Double bonds with R-sites are excluded because cis-trans configuration 
   // cannot be determined when R-site is substituted with R-group
   if (mol.isRSite(beg_idx) || mol.isRSite(end_idx))
      return false;

   // the atoms should have 1 or 2 single bonds
   // (apart from the double bond under consideration)
   const Vertex &beg = mol.getVertex(beg_idx);
   const Vertex &end = mol.getVertex(end_idx);

   if (beg.degree() < 2 || beg.degree() > 3 ||
       end.degree() < 2 || end.degree() > 3)
      return false;

   substituents[0] = -1;
   substituents[1] = -1;
   substituents[2] = -1;
   substituents[3] = -1;

   int i;

   for (i = beg.neiBegin(); i != beg.neiEnd(); i = beg.neiNext(i))
   {
      int nei_edge_idx = beg.neiEdge(i);

      if (nei_edge_idx == bond_idx)
         continue;
      
      if (!mol.possibleBondOrder(nei_edge_idx, BOND_SINGLE))
         return false;

      if (substituents[0] == -1)
         substituents[0] = beg.neiVertex(i);
      else // (substituents[1] == -1)
         substituents[1] = beg.neiVertex(i);
   }

   for (i = end.neiBegin(); i != end.neiEnd(); i = end.neiNext(i))
   {
      int nei_edge_idx = end.neiEdge(i);

      if (nei_edge_idx == bond_idx)
         continue;
      
      if (!mol.possibleBondOrder(nei_edge_idx, BOND_SINGLE))
         return false;

      if (substituents[2] == -1)
         substituents[2] = end.neiVertex(i);
      else // (substituents[3] == -1)
         substituents[3] = end.neiVertex(i);
   }

   // Check trianges when substituents are the same: CC1=C(N)C1
   if (substituents[0] >= 0)
      if (substituents[0] == substituents[2] || substituents[0] == substituents[3])
         return false;
   if (substituents[1] >= 0)
      if (substituents[1] == substituents[2] || substituents[1] == substituents[3])
         return false;

   if (have_xyz)
   {
      if (substituents[1] != -1 &&
          _sameside(mol, beg_idx, end_idx, substituents[0], substituents[1]) != -1)
         return false;
      else if (_sameline(mol, beg_idx, end_idx, substituents[0]))
         return false;

      if (substituents[3] != -1 &&
          _sameside(mol, beg_idx, end_idx, substituents[2], substituents[3]) != -1)
         return false;
      else if (_sameline(mol, beg_idx, end_idx, substituents[2]))
         return false;
   }

   return true;
}
bool MoleculeExactMatcher::matchAtoms (BaseMolecule& query, BaseMolecule& target, int sub_idx, int super_idx, int flags)
{
   if (query.isRSite(sub_idx) && target.isRSite(super_idx))
      return query.getRSiteBits(sub_idx) == target.getRSiteBits(super_idx);

   if (query.isRSite(sub_idx) || target.isRSite(super_idx))
      return false;

   if (query.isPseudoAtom(sub_idx) && target.isPseudoAtom(super_idx))
   {
      if (strcmp(query.getPseudoAtom(sub_idx), target.getPseudoAtom(super_idx)) != 0)
         return false;
   }
   else if (query.isTemplateAtom(sub_idx) && target.isTemplateAtom(super_idx))
   {
      if (strcmp(query.getTemplateAtom(sub_idx), target.getTemplateAtom(super_idx)) != 0)
         return false;
   }
   else if (!query.isPseudoAtom(sub_idx) && !target.isPseudoAtom(super_idx) &&
            !query.isTemplateAtom(sub_idx) && !target.isTemplateAtom(super_idx))
   {
      if (query.getAtomNumber(sub_idx) != target.getAtomNumber(super_idx))
         return false;
   }
   else
      return false;

   if (flags & CONDITION_ISOTOPE)
      if (query.getAtomIsotope(sub_idx) != target.getAtomIsotope(super_idx))
         return false;

   if (flags & CONDITION_ELECTRONS)
   {
      int qcharge = query.getAtomCharge(sub_idx);
      int tcharge = target.getAtomCharge(super_idx);

      if (qcharge == CHARGE_UNKNOWN)
         qcharge = 0;
      if (tcharge == CHARGE_UNKNOWN)
         tcharge = 0;

      if (qcharge != tcharge)
         return false;

      if (!query.isPseudoAtom(sub_idx) && !query.isTemplateAtom(sub_idx))
      {
         if (!query.isQueryMolecule() && !target.isQueryMolecule())
         {
            if (query.getAtomValence(sub_idx) != target.getAtomValence(super_idx))
               return false;
         }      
         
         int qrad = query.getAtomRadical(sub_idx);
         int trad = target.getAtomRadical(super_idx);

         if (qrad == -1)
            qrad = 0;
         if (trad == -1)
            trad = 0;

         if (qrad != trad)
            return false;

         if (query.isQueryMolecule())
         {
            int qarom = query.getAtomAromaticity(sub_idx);
            int tarom = target.getAtomAromaticity(super_idx);

            if (qarom != -1 && tarom != -1)
               if (qarom != tarom)
                  return false;
         }
      }
   }

   if (flags & CONDITION_STEREO)
   {
      int qtype = query.stereocenters.getType(sub_idx);

      if (qtype != target.stereocenters.getType(super_idx))
         return false;
   }
   return true;
}
Esempio n. 13
0
bool MoleculeCisTrans::_pureH (BaseMolecule &mol, int idx)
{
   return mol.getAtomNumber(idx) == ELEM_H && mol.getAtomIsotope(idx) == 0;
}
Esempio n. 14
0
void _getBounds (RenderParams& params, BaseMolecule &mol, Vec2f &min, Vec2f &max, float &scale)
{
   // Compute average bond length
   float avg_bond_length = 1;
   if (mol.edgeCount() > 0)
   {
      float bond_length_sum = 0;
      for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i))
      {
         const Edge& edge = mol.getEdge(i);
         const Vec3f &p1 = mol.getAtomXyz(edge.beg);
         const Vec3f &p2 = mol.getAtomXyz(edge.end);
         bond_length_sum += Vec3f::dist(p1, p2);
      }
      avg_bond_length = bond_length_sum / mol.edgeCount();
   }

   float bond_length = 1;
   if (params.cnvOpt.bondLength > 0)
      bond_length = params.cnvOpt.bondLength / 100.0f;

   scale = bond_length / avg_bond_length;

   for (int i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
   {
      Vec3f &p = mol.getAtomXyz(i);
      Vec2f p2(p.x, p.y);

      if (i == mol.vertexBegin())
         min = max = p2;
      else
      {
         min.min(p2);
         max.max(p2);
      }
   }

   min.scale(scale);
   max.scale(scale);
}
Esempio n. 15
0
void _placeSGroupBracketsCrossBonds (Array<Vec2f[2]>& brackets, BaseMolecule& mol, const Array<int>& atoms, const Array<int>& crossBonds, const Array<bool>& crossBondOut, float bondLength)
{
   brackets.clear();
   if (crossBonds.size() == 2) {
      int bid1 = crossBonds[0], bid2 = crossBonds[1];
      const Edge& edge1 =  mol.getEdge(bid1);
      const Edge& edge2 =  mol.getEdge(bid2);
      Vec2f pb1, pe1, pb2, pe2;
      Vec2f::projectZ(pb1, mol.getAtomXyz(edge1.beg));
      Vec2f::projectZ(pe1, mol.getAtomXyz(edge1.end));
      Vec2f::projectZ(pb2, mol.getAtomXyz(edge2.beg));
      Vec2f::projectZ(pe2, mol.getAtomXyz(edge2.end));
      Vec2f d1, d2;
      d1.diff(pe1, pb1);
      if (!crossBondOut[0])
         d1.scale(-1);
      d1.normalize();
      d2.diff(pe2, pb2);
      if (!crossBondOut[1])
         d2.scale(-1);
      d2.normalize();
      if (Vec2f::dot(d1, d2) < -0.3) {
         Vec2f d, n;
         d.add(pb1);
         d.add(pe1);
         d.sub(pb2);
         d.sub(pe2);
         d.normalize();
         n.copy(d);
         n.rotate(1, 0);
         Vec2f min, max, a, b, c;
         c.add(pb1);
         c.add(pe1);
         c.add(pb2);
         c.add(pe2);
         c.scale(0.25f);
         for (int i = 0; i < atoms.size(); ++i) {
            int aid = atoms[i];
            const Vec3f& pos = mol.getAtomXyz(aid);
            Vec2f p2d;
            Vec2f::projectZ(p2d, pos);
            p2d.sub(c);
            p2d.set(Vec2f::dot(p2d, d), Vec2f::dot(p2d, n));
            if (i == 0) {
               min.copy(p2d);
               max.copy(p2d);
            } else {
               min.min(p2d);
               max.max(p2d);
            }
         }
         Vec2f b1(c), b2;
         b1.addScaled(d, max.x + 0.3f * bondLength);
         b2.copy(b1);
         float factor = 0.5;
         b1.addScaled(n, factor * bondLength);
         b2.addScaled(n, -factor * bondLength);
         Vec2f* const & bracket1 = brackets.push();
         bracket1[0].copy(b1);
         bracket1[1].copy(b2);

         b1.copy(c);
         b1.addScaled(d, min.x - 0.3f * bondLength);
         b2.copy(b1);
         b1.addScaled(n, -factor * bondLength);
         b2.addScaled(n, factor * bondLength);
         Vec2f* const & bracket2 = brackets.push();
         bracket2[0].copy(b1);
         bracket2[1].copy(b2);
         return;
      }
   }
   for (int i = 0; i < crossBonds.size(); ++i) {
      int bid = crossBonds[i];
      const Edge& edge =  mol.getEdge(bid);
      int aidIn = edge.beg, aidOut = edge.end;
      if (!crossBondOut[i]) {
         int t;
         __swap(aidIn, aidOut, t);
      }
      Vec2f p2dIn, p2dOut, d, n, b1, b2;
      Vec2f::projectZ(p2dIn, mol.getAtomXyz(aidIn));
      Vec2f::projectZ(p2dOut, mol.getAtomXyz(aidOut));
      d.diff(p2dOut, p2dIn);
      d.normalize();
      n.copy(d);
      n.rotate(1, 0);
      float offset = 1.0f / 3;
      b1.lineCombin2(p2dIn, 1 - offset, p2dOut, offset);
      b2.copy(b1);
      float factor = 0.5;
      b1.addScaled(n, factor * bondLength);
      b2.addScaled(n, -factor * bondLength);
      Vec2f* const & bracket = brackets.push();
      bracket[0].copy(b1);
      bracket[1].copy(b2);
   }
}
Esempio n. 16
0
void QueryMolecule::_mergeWithSubmolecule (BaseMolecule &bmol, const Array<int> &vertices,
           const Array<int> *edges, const Array<int> &mapping, int skip_flags)
{
   QueryMolecule &mol = bmol.asQueryMolecule();
   int i;

   // atoms
   for (i = 0; i < vertices.size(); i++)
   {
      int newidx = mapping[vertices[i]];

      _atoms.expand(newidx + 1);
      _atoms.set(newidx, mol.getAtom(vertices[i]).clone());
   }
      
   // bonds
   if (edges != 0)
      for (i = 0; i < edges->size(); i++)
      {
         const Edge &edge = mol.getEdge(edges->at(i));
         int beg = mapping[edge.beg];
         int end = mapping[edge.end];

         if (beg == -1 || end == -1)
            // must have been thrown before in mergeWithSubgraph()
            throw Error("_mergeWithSubmolecule: internal");

         int idx = findEdgeIndex(beg, end);

         _bonds.expand(idx + 1);
         _bonds.set(idx, mol.getBond(edges->at(i)).clone());

         // Aromaticity
         if (!(skip_flags & SKIP_AROMATICITY))
            aromaticity.setCanBeAromatic(idx, mol.aromaticity.canBeAromatic(edges->at(i)));
         if (!(skip_flags & SKIP_CIS_TRANS) && mol.cis_trans.getParity(edges->at(i)) != 0)
            setBondStereoCare(idx, mol.bondStereoCare(edges->at(i)));
      }
   else
      for (i = mol.edgeBegin(); i < mol.edgeEnd(); i = mol.edgeNext(i))
      {
         const Edge &edge = mol.getEdge(i);
         int beg = mapping[edge.beg];
         int end = mapping[edge.end];

         if (beg == -1 || end == -1)
            continue;

         int idx = findEdgeIndex(beg, end);

         _bonds.expand(idx + 1);
         _bonds.set(idx, mol.getBond(i).clone());

         // Aromaticity
         if (!(skip_flags & SKIP_AROMATICITY))
            aromaticity.setCanBeAromatic(idx, mol.aromaticity.canBeAromatic(i));
         if (!(skip_flags & SKIP_CIS_TRANS) && mol.cis_trans.getParity(i) != 0)
            setBondStereoCare(idx, mol.bondStereoCare(i));
      }

   // 3D constraints
   if (!(skip_flags & SKIP_3D_CONSTRAINTS))
      spatial_constraints.buildOnSubmolecule(mol.spatial_constraints, mapping.ptr());

   // fixed atoms
   if (!(skip_flags & SKIP_FIXED_ATOMS))
   {
      for (i = 0; i < mol.fixed_atoms.size(); i++)
      {
         int idx = mapping[mol.fixed_atoms[i]];

         if (idx >= 0)
            fixed_atoms.push(idx);
      }
   }

   // components
   if (!(skip_flags & SKIP_COMPONENTS))
   {
      for (i = 0; i < vertices.size(); i++)
      {
         int v_idx = vertices[i];
         if (mol.components.size() > v_idx)
         {
            int newidx = mapping[v_idx];
            components.expandFill(newidx + 1, 0);
            components[newidx] = mol.components[v_idx];
         }
      }
   }

   updateEditRevision();
}
bool MoleculeSubstructureMatcher::matchQueryAtom
         (QueryMolecule::Atom *query, BaseMolecule &target, int super_idx,
         FragmentMatchCache *fmcache, dword flags)
{
   int i;

   switch (query->type)
   {
      case QueryMolecule::OP_NONE:
         return true;
      case QueryMolecule::OP_AND:
         for (i = 0; i < query->children.size(); i++)
            if (!matchQueryAtom(query->child(i), target, super_idx, fmcache, flags))
               return false;
         return true;
      case QueryMolecule::OP_OR:
         for (i = 0; i < query->children.size(); i++)
            if (matchQueryAtom(query->child(i), target,
                               super_idx, fmcache, flags))
               return true;
         return false;
      case QueryMolecule::OP_NOT:
         return !matchQueryAtom(query->child(0), target, super_idx, fmcache,
                                flags ^ MATCH_DISABLED_AS_TRUE);

      case QueryMolecule::ATOM_NUMBER:
         return query->valueWithinRange(target.getAtomNumber(super_idx));
      case QueryMolecule::ATOM_PSEUDO:
         return target.isPseudoAtom(super_idx) &&
                 strcmp(query->alias.ptr(), target.getPseudoAtom(super_idx)) == 0;
      case QueryMolecule::ATOM_RSITE:
         return true;
      case QueryMolecule::ATOM_ISOTOPE:
         return query->valueWithinRange(target.getAtomIsotope(super_idx));
      case QueryMolecule::ATOM_CHARGE:
      {
         if (flags & MATCH_ATOM_CHARGE)
            return query->valueWithinRange(target.getAtomCharge(super_idx));
         return (flags & MATCH_DISABLED_AS_TRUE) != 0;
      }
      case QueryMolecule::ATOM_RADICAL:
      {
         if (target.isPseudoAtom(super_idx) || target.isRSite(super_idx))
            return false;
         return query->valueWithinRange(target.getAtomRadical(super_idx));
      }
      case QueryMolecule::ATOM_VALENCE:
      {
         if (flags & MATCH_ATOM_VALENCE)
         {
            if (target.isPseudoAtom(super_idx) || target.isRSite(super_idx))
               return false;
            return query->valueWithinRange(target.getAtomValence(super_idx));
         }
         return (flags & MATCH_DISABLED_AS_TRUE) != 0;
      }
      case QueryMolecule::ATOM_CONNECTIVITY:
      {
         int conn = target.getVertex(super_idx).degree();
         if (!target.isPseudoAtom(super_idx) && !target.isRSite(super_idx))
            conn += target.asMolecule().getImplicitH(super_idx);
         return query->valueWithinRange(conn);
      }
      case QueryMolecule::ATOM_TOTAL_BOND_ORDER:
      {
         // TODO: target.isPseudoAtom(super_idx) || target.isRSite(super_idx)
         return query->valueWithinRange(target.asMolecule().getAtomConnectivity(super_idx));
      }
      case QueryMolecule::ATOM_TOTAL_H:
      {
         if (target.isPseudoAtom(super_idx) || target.isRSite(super_idx))
            return false;
         return query->valueWithinRange(target.getAtomTotalH(super_idx));
      }
      case QueryMolecule::ATOM_SUBSTITUENTS:
         return query->valueWithinRange(target.getAtomSubstCount(super_idx));
      case QueryMolecule::ATOM_SSSR_RINGS:
         return query->valueWithinRange(target.vertexCountSSSR(super_idx));
      case QueryMolecule::ATOM_SMALLEST_RING_SIZE:
         return query->valueWithinRange(target.vertexSmallestRingSize(super_idx));
      case QueryMolecule::ATOM_RING_BONDS:
      case QueryMolecule::ATOM_RING_BONDS_AS_DRAWN:
         return query->valueWithinRange(target.getAtomRingBondsCount(super_idx));
      case QueryMolecule::ATOM_UNSATURATION:
         return !target.isSaturatedAtom(super_idx);
      case QueryMolecule::ATOM_FRAGMENT:
      {
         if (fmcache == 0)
            throw Error("unexpected 'fragment' constraint");

         QueryMolecule *fragment = query->fragment.get();
         const char *smarts = fragment->fragment_smarts.ptr();

         if (fragment->vertexCount() == 0)
            throw Error("empty fragment");

         if (smarts != 0 && strlen(smarts) > 0)
         {
            fmcache->expand(super_idx + 1);
            int *value = fmcache->at(super_idx).at2(smarts);

            if (value != 0)
               return *value != 0;
         }

         
         MoleculeSubstructureMatcher matcher(target.asMolecule());

         matcher.not_ignore_first_atom = true;
         matcher.setQuery(*fragment);
         matcher.fmcache = fmcache;

         bool result = matcher.fix(fragment->vertexBegin(), super_idx);

         if (result)
            result = matcher.find();

         if (smarts != 0 && strlen(smarts) > 0)
         {
            fmcache->expand(super_idx + 1);
            fmcache->at(super_idx).insert(smarts, result ? 1 : 0);
         }

         return result;
      }
      case QueryMolecule::ATOM_AROMATICITY:
         return query->valueWithinRange(target.getAtomAromaticity(super_idx));
      case QueryMolecule::HIGHLIGHTING:
         return query->valueWithinRange((int)target.isAtomHighlighted(super_idx));
      default:
         throw Error("bad query atom type: %d", query->type);
   }
}
Esempio n. 18
0
void MoleculeAutoLoader::_loadMolecule (BaseMolecule &mol, bool query)
{
   properties.clear();

   // check for GZip format
   if (!query && _scanner->length() >= 2)
   {
      byte id[2];
      int pos = _scanner->tell();

      _scanner->readCharsFix(2, (char *)id);
      _scanner->seek(pos, SEEK_SET);

      if (id[0] == 0x1f && id[1] == 0x8b)
      {
         GZipScanner gzscanner(*_scanner);
         QS_DEF(Array<char>, buf);

         gzscanner.readAll(buf);
         MoleculeAutoLoader loader2(buf);

         loader2.ignore_stereocenter_errors = ignore_stereocenter_errors;
         loader2.ignore_noncritical_query_features = ignore_noncritical_query_features;
         loader2.treat_x_as_pseudoatom = treat_x_as_pseudoatom;
         loader2.skip_3d_chirality = skip_3d_chirality;
         loader2.loadMolecule((Molecule &)mol);
         return;
      }
   }

   // check for MDLCT format
   {
      QS_DEF(Array<char>, buf);
      if (tryMDLCT(*_scanner, buf))
      {
         BufferScanner scanner2(buf);
         MolfileLoader loader(scanner2);
         loader.ignore_stereocenter_errors = ignore_stereocenter_errors;
         loader.ignore_noncritical_query_features = ignore_noncritical_query_features;
         loader.skip_3d_chirality = skip_3d_chirality;
         loader.treat_x_as_pseudoatom = treat_x_as_pseudoatom;

         if (query)
            loader.loadQueryMolecule((QueryMolecule &)mol);
         else
            loader.loadMolecule((Molecule &)mol);
         return;
      }
   }

   // check for ICM format
   if (!query && _scanner->length() >= 4)
   {
      char id[3];
      int pos = _scanner->tell();

      _scanner->readCharsFix(3, id);
      _scanner->seek(pos, SEEK_SET);
      if (IcmSaver::checkVersion(id))
      {
         if (query)
            throw Error("cannot load query molecule from ICM format");

         IcmLoader loader(*_scanner);
         loader.loadMolecule((Molecule &)mol);
         return;
      }
   }

   // check for CML format
   {
      int pos = _scanner->tell();
      _scanner->skipSpace();

      if (_scanner->lookNext() == '<')
      {
         if (_scanner->findWord("<molecule"))
         {
            MoleculeCmlLoader loader(*_scanner);
            loader.ignore_stereochemistry_errors = ignore_stereocenter_errors;
            if (query)
               throw Error("CML queries not supported");
            loader.loadMolecule(mol.asMolecule());
            return;
         }
      }

      _scanner->seek(pos, SEEK_SET);
   }

   // check for SMILES format
   if (Scanner::isSingleLine(*_scanner))
   {
      SmilesLoader loader(*_scanner);

      loader.ignore_closing_bond_direction_mismatch =
             ignore_closing_bond_direction_mismatch;
      loader.ignore_stereochemistry_errors = ignore_stereocenter_errors;
      if (query)
         loader.loadQueryMolecule((QueryMolecule &)mol);
      else
         loader.loadMolecule((Molecule &)mol);
      return;
   }

   // default is Molfile format
   {
      SdfLoader sdf_loader(*_scanner);
      sdf_loader.readNext();

      // Copy properties
      properties.copy(sdf_loader.properties);

      BufferScanner scanner2(sdf_loader.data);

      MolfileLoader loader(scanner2);
      loader.ignore_stereocenter_errors = ignore_stereocenter_errors;
      loader.ignore_noncritical_query_features = ignore_noncritical_query_features;
      loader.skip_3d_chirality = skip_3d_chirality;
      loader.treat_x_as_pseudoatom = treat_x_as_pseudoatom;

      if (query)
         loader.loadQueryMolecule((QueryMolecule &)mol);
      else
         loader.loadMolecule((Molecule &)mol);
   }
}
int MoleculeSubstructureMatcher::_compare_degree_asc (BaseMolecule &mol, int i1, int i2)
{
   return mol.getVertex(i2).degree() - mol.getVertex(i1).degree();
}
void MoleculeSubstructureMatcher::markIgnoredHydrogens (BaseMolecule &mol, int *arr, int value_keep, int value_ignore)
{
   int i;

   for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
      arr[i] = value_keep;

   for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
   {
      if (mol.getAtomNumber(i) != ELEM_H)
         continue;

      if (!mol.possibleAtomIsotope(i, 0))
         continue;

      if (mol.isQueryMolecule())
      {
         // Check if atom has fragment constraint.
         // For example [$([#1][N])] should be ignored
         if (mol.asQueryMolecule().getAtom(i).hasConstraint(QueryMolecule::ATOM_FRAGMENT))
            continue;
      }

      const Vertex &vertex = mol.getVertex(i);

      if (vertex.degree() == 1)
      {
         int nei_idx = vertex.neiVertex(vertex.neiBegin());

         if (mol.getAtomNumber(nei_idx) == ELEM_H && mol.possibleAtomIsotope(nei_idx, 0))
            continue; // do not ignore rare H-H fragment

         // Check if hydrogen forms a cis-trans bond or stereocenter
         int nei_vertex_idx = vertex.neiVertex(vertex.neiBegin());
         if (mol.stereocenters.exists(nei_vertex_idx))
            continue;

         // For example for this query hydrogens should be unfolded: [H]\\C=C/C
         const Vertex &nei_vertex = mol.getVertex(nei_vertex_idx);
         bool not_ignore = false;
         for (int nei = nei_vertex.neiBegin(); nei != nei_vertex.neiEnd(); nei = nei_vertex.neiNext(nei))
         {
            int edge = nei_vertex.neiEdge(nei);
            if (mol.cis_trans.getParity(edge) != 0)
            {
               not_ignore = true;
               break;
            }
         }
         if (not_ignore)
            continue;

         arr[i] = value_ignore;
      }
   }
}
Esempio n. 21
0
bool TautomerRule::check (BaseMolecule &molecule, int first_idx, int last_idx,
                          char other_arom_first, char other_arom_last)  const
{
    if (first_idx != -1 && last_idx != -1)
    {
        int first_atom = molecule.getAtomNumber(first_idx);
        int last_atom = molecule.getAtomNumber(last_idx);

        if (list1.find(first_atom) >= 0)
        {
            if (aromaticity1 == -1 ||
                    (aromaticity1 == 1 && (atomInAromaticRing(molecule, first_idx) || other_arom_first == 1)) ||
                    (aromaticity1 == 0 && !atomInAromaticRing(molecule, first_idx)))
            {
                if (list2.find(last_atom) >= 0)
                {
                    if (aromaticity2 == -1 ||
                            (aromaticity2 == 1 && (atomInAromaticRing(molecule, last_idx) || other_arom_last == 1)) ||
                            (aromaticity2 == 0 && !atomInAromaticRing(molecule, last_idx)))
                    {
                        return true;
                    }
                }
            }
        }

        if (list2.find(first_atom) >= 0)
        {
            if (aromaticity2 == -1 ||
                    (aromaticity2 == 1 && (atomInAromaticRing(molecule, first_idx) || other_arom_first == 1)) ||
                    (aromaticity2 == 0 && !atomInAromaticRing(molecule, first_idx)))
            {
                if (list1.find(last_atom) >= 0)
                {
                    if (aromaticity1 == -1 ||
                            (aromaticity1 == 1 && (atomInAromaticRing(molecule, last_idx) || other_arom_last == 1)) ||
                            (aromaticity1 == 0 && !atomInAromaticRing(molecule, last_idx)))
                    {
                        return true;
                    }
                }
            }
        }

        return false;
    } else if (first_idx != -1 || last_idx != -1)
    {
        if (first_idx == -1)
            first_idx = last_idx;

        int first_atom = molecule.getAtomNumber(first_idx);

        if (list1.find(first_atom) >= 0)
            if (aromaticity1 == -1 ||
                    (aromaticity1 == 1 && (atomInAromaticRing(molecule, first_idx) || other_arom_first == 1)) ||
                    (aromaticity1 == 0 && !atomInAromaticRing(molecule, first_idx)))
                return true;

        if (list2.find(first_atom) >= 0)
            if (aromaticity2 == -1 ||
                    (aromaticity2 == 1 && (atomInAromaticRing(molecule, first_idx) || other_arom_first == 1)) ||
                    (aromaticity2 == 0 && !atomInAromaticRing(molecule, first_idx)))
                return true;

        return false;
    }

    return true;
}
Esempio n. 22
0
void MoleculeFingerprintBuilder::_calcExtraBits (BaseMolecule &mol, Filter &vfilter)
{
   int counters[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
   int i;

   for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i))
   {
      if (!vfilter.valid(i))
         continue;

      int an = mol.getAtomNumber(i);

      if (an == ELEM_C)
         counters[0]++;
      else if (an == ELEM_N)
         counters[1]++;
      else if (an == ELEM_O)
         counters[2]++;
      else if (an == ELEM_P)
         counters[3]++;
      else if (an == ELEM_S)
         counters[4]++;
      else if (Element::isHalogen(an))
         counters[5]++;
      else if (an > ELEM_H)
         counters[6]++;

      if (!skip_ext_charge && mol.getAtomCharge(i) != 0 && mol.getAtomCharge(i) != CHARGE_UNKNOWN)
         counters[7]++;
      if (mol.getAtomIsotope(i) > 0)
         counters[8]++;
   }
   
   byte *fp = _total_fingerprint.ptr();

   if (counters[0] > 13) // > 13 C
      fp[0] |= 1;
   if (counters[0] > 16) // > 16 C
      fp[0] |= 2;
   if (counters[0] > 19) // > 19 C
      fp[0] |= 4;
   if (counters[1] > 1) // > 1 N
      fp[0] |= 8;
   if (counters[1] > 2) // > 2 N
      fp[0] |= 16;
   if (counters[2] > 3) // > 3 O
      fp[0] |= 32;
   if (counters[2] > 4) // > 4 O
      fp[0] |= 64;
   if (counters[3] > 0) // have P
      fp[0] |= 128;
   if (counters[4] > 0) // have S
      fp[1] |= 1;
   if (counters[4] > 1) // > 1 S
      fp[1] |= 2;
   if (counters[5] > 1) // > 1 halogen
      fp[1] |= 4;
   if (counters[5] > 2) // > 2 halogen
      fp[1] |= 8;
   if (counters[6] > 0) // have rare atoms
      fp[1] |= 16;
   if (counters[6] > 1) // > 1 rare atom
      fp[1] |= 32;
   if (counters[7] > 0) // have charged atoms
      fp[1] |= 64;
   if (counters[8] > 1) // have isotopes
      fp[1] |= 128;
}