Skip to content

Commit

Permalink
Added initial tool_rings plugin, implementing ring search algorithm i…
Browse files Browse the repository at this point in the history
…n Phys. Rev. B 1991, 44, 4925. Added Pattern::findRingsFrom() to search for rings from specific atom in pattern. Modified Pattern::findRings() to accept maxRingSize and maxRings as arguments. Added forceFull default argument to Pattern::createMatrices(). Added Pattern::connectivity() to return distance between supplied atoms (in terms of edges). Fixed - QCustomPlot was not being compiled correctly. Modified Pattern::createMatrices() to form connectivity matrix without requiring PatternBound arrays to have been previously formed.
  • Loading branch information
trisyoungs committed Mar 19, 2017
1 parent db15146 commit 478fddd
Show file tree
Hide file tree
Showing 26 changed files with 1,409 additions and 61 deletions.
11 changes: 6 additions & 5 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -106,23 +106,24 @@ AC_CHECK_HEADER([$RLINCDIR/readline.h],,[AC_MSG_ERROR([Cannot find headers for r

# Set up compilation for Qt GUI
if test "$with_qt" = "framework"; then
QTGUI_LIBS="-framework QtGui -framework QtOpenGL -framework QtCore -framework OpenGL"
QTGUI_CFLAGS="-F QtGui -F QtOpenGl -F QtCore"
QTGUI_LIBS="-framework QtGui -framework QtOpenGL -framework QtCore -framework QtPrintSupport -framework OpenGL"
QTGUI_CFLAGS="-F QtGui -F QtOpenGl -F QtCore -FQtPrintSupport"
fi
if test "x$with_qt" = "x"; then
PKG_CHECK_MODULES(QTGUI, Qt5Gui >= 5.0.0)
PKG_CHECK_MODULES(QTOPENGL, Qt5OpenGL >= 5.0.0)
PKG_CHECK_MODULES(QTWIDGETS, Qt5Widgets >= 5.0.0)
PKG_CHECK_MODULES(QTPRINT, Qt5PrintSupport >= 5.0.0)
fi

# Finalise substitution strings
ATEN_LDLIBS="$FTGL_LIBS $FREETYPE_LIBS $QTGUI_LIBS $QTOPENGL_LIBS -lreadline -lGL -lfreetype"
ATEN_CFLAGS="-fPIC $CHECK_CFLAGS $CXXFLAGS"
ATEN_LDLIBS="$FTGL_LIBS $FREETYPE_LIBS $QTGUI_LIBS $QTOPENGL_LIBS $QTPRINT_LIBS -lreadline -lGL -lfreetype"
ATEN_CFLAGS="-fPIC $CHECK_CFLAGS $CXXFLAGS" # -DQCUSTOMPLOT_COMPILE_LIBRARY -DQCUSTOMPLOT_USE_LIBRARY"
ATEN_LDFLAGS="$LDFLAGS"
if test "$with_nordynamic" = "no"; then
ATEN_LDFLAGS+=" -rdynamic "
fi
ATEN_INCLUDES=" $FREETYPE_CFLAGS $QTGUI_CFLAGS $QTWIDGETS_CFLAGS -I$RLINCDIR"
ATEN_INCLUDES=" $FREETYPE_CFLAGS $QTGUI_CFLAGS $QTWIDGETS_CFLAGS $QTPRINT_CFLAGS -I$RLINCDIR"

# Perform Makefile substitutions
AC_SUBST(ATEN_LDLIBS)
Expand Down
2 changes: 1 addition & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ SUBDIRS = gui templates base sg math model undo ff methods render command parser

noinst_LTLIBRARIES = libaten.la
libaten_la_SOURCES =
libaten_la_LIBADD = base/libmessenger.la gui/qcustomplot/libqcustomplot.la gui/libgui.la parser/libparser.la gui/libtreegui.la command/libcommand.la methods/libmethods.la model/libmodel.la undo/libundo.la render/librender.la math/libmath.la main/libmain.la plugins/libplugins.la ff/libff.la base/libbase.la sg/libsg.la base/libfourierdata.la
libaten_la_LIBADD = base/libmessenger.la gui/libgui.la gui/qcustomplot/libqcustomplot.la parser/libparser.la gui/libtreegui.la command/libcommand.la methods/libmethods.la model/libmodel.la undo/libundo.la render/librender.la math/libmath.la main/libmain.la plugins/libplugins.la ff/libff.la base/libbase.la sg/libsg.la base/libfourierdata.la
libaten_la_LDFLAGS = -static

aten_LDADD = libaten.la @ATEN_LDLIBS@ @ATEN_LDFLAGS@
Expand Down
8 changes: 4 additions & 4 deletions src/base/neta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ int Neta::matchAtom(Atom* i, List<Ring>* rings, Model* parent)
RefList<Atom,int> boundList;
i->addBoundToRefList(&boundList);
RefList<Ring,int> ringList;
if (targetRingList_) for (Ring *r = targetRingList_->first(); r != NULL; r = r->next) if (r->containsAtom(i)) ringList.add(r);
if (targetRingList_) for (Ring* r = targetRingList_->first(); r != NULL; r = r->next) if (r->containsAtom(i)) ringList.add(r);
RefList<Atom,int> path;
int score = description_->score(i, &boundList, &ringList, description_, path, 0);
// printf("Score is %i\n", score);
Expand Down Expand Up @@ -838,7 +838,7 @@ int NetaBoundNode::score(Atom* target, RefList<Atom,int>* nbrs, RefList<Ring,int
ri->item->addBoundToRefList(&boundList);
// Construct new ringlist
RefList<Ring,int> ringList;
for (Ring *r = parent()->targetRingList()->first(); r != NULL; r = r->next) if (r->containsAtom(ri->item)) ringList.add(r);
for (Ring* r = parent()->targetRingList()->first(); r != NULL; r = r->next) if (r->containsAtom(ri->item)) ringList.add(r);
path.add(target);
boundscore = innerNeta_->score(ri->item, &boundList, &ringList, this, path, level+1);
path.removeLast();
Expand Down Expand Up @@ -912,7 +912,7 @@ int NetaKeywordNode::score(Atom* target, RefList<Atom,int>* nbrs, RefList<Ring,i
else
{
totalscore = 1;
for (Ring *r = parent()->targetRingList()->first(); r != NULL; r = r->next) if (r->containsAtom(target)) totalscore = -1;
for (Ring* r = parent()->targetRingList()->first(); r != NULL; r = r->next) if (r->containsAtom(target)) totalscore = -1;
}
break;
case (Neta::NonAromaticKeyword):
Expand Down Expand Up @@ -1245,7 +1245,7 @@ NetaRingNode::~NetaRingNode()
}

// Retrieve current ring under consideration
Ring *NetaRingNode::currentRing()
Ring* NetaRingNode::currentRing()
{
return currentRing_;
}
Expand Down
4 changes: 2 additions & 2 deletions src/base/neta.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,11 +386,11 @@ class NetaRingNode : public NetaContextNode

private:
// Current ring under consideration
Ring *currentRing_;
Ring* currentRing_;

public:
// Retrieve current ring under consideration
Ring *currentRing();
Ring* currentRing();
// Validation function (virtual)
int score(Atom* target, RefList<Atom,int>* nbrs, RefList<Ring,int>* rings, NetaContextNode* context, RefList<Atom,int>& path, int level);
// Print node contents
Expand Down
127 changes: 95 additions & 32 deletions src/base/pattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ int Pattern::nRings()
}

// Returns the first ring in the ring list
Ring *Pattern::rings()
Ring* Pattern::rings()
{
return rings_.first();
}
Expand All @@ -580,13 +580,13 @@ bool Pattern::atomsInRing(int id_i, int id_j)
if (id_j == -1)
{
Atom* i = atoms_[id_i]->atom();
for (Ring *r = rings_.first(); r != NULL; r = r->next) if (r->containsAtom(i)) return true;
for (Ring* r = rings_.first(); r != NULL; r = r->next) if (r->containsAtom(i)) return true;
}
else
{
Atom* i = atoms_[id_i]->atom();
Atom* j = atoms_[id_j]->atom();
for (Ring *r = rings_.first(); r != NULL; r = r->next) if ((r->containsAtom(i)) && (r->containsAtom(j))) return true;
for (Ring* r = rings_.first(); r != NULL; r = r->next) if ((r->containsAtom(i)) && (r->containsAtom(j))) return true;
}
return false;
}
Expand All @@ -596,11 +596,11 @@ bool Pattern::atomsInRing(Atom* i, Atom* j)
{
if (j == NULL)
{
for (Ring *r = rings_.first(); r != NULL; r = r->next) if (r->containsAtom(i)) return true;
for (Ring* r = rings_.first(); r != NULL; r = r->next) if (r->containsAtom(i)) return true;
}
else
{
for (Ring *r = rings_.first(); r != NULL; r = r->next) if ((r->containsAtom(i)) && (r->containsAtom(j))) return true;
for (Ring* r = rings_.first(); r != NULL; r = r->next) if ((r->containsAtom(i)) && (r->containsAtom(j))) return true;
}
return false;
}
Expand Down Expand Up @@ -699,7 +699,7 @@ void Pattern::deleteExpression()
}

// Create connectivity and scaling matrices for molecules in pattern
void Pattern::createMatrices()
void Pattern::createMatrices(bool forceFull)
{
Messenger::enter("Pattern::createMatrices");
int n, m, a1, a2;
Expand All @@ -719,24 +719,27 @@ void Pattern::createMatrices()
for (n=0; n<nAtoms_; ++n)
for (m=0; m<nAtoms_; ++m) conMatrix_[n][m] = 0;

// Print out the bonding matrix
/* printf("Bonding Matrix\n");
for (n=0; n<nAtoms_; n++)
{
for (m=0; m<nAtoms_; m++) printf (" %2i ",conMatrix_[n][m]);
printf("\n");
} */

// Since the full transformation to the connectivity matrix is quite intensive, we will only do this for patterns containing less than 1000 atoms
if (nAtoms_ < 1000)
if (forceFull || (nAtoms_ < 1000))
{
Messenger::print("seeding.....");
// First, build up the bond matrix
for (pb = bonds_.first(); pb != NULL; pb = pb->next)
Atom* i = firstAtom_;
int ii = i->id();
for (n=0; n<nAtoms_; ++n)
{
conMatrix_[ pb->atomId(0) ] [ pb->atomId(1) ] = 1;
conMatrix_[ pb->atomId(1) ] [ pb->atomId(0) ] = 1;
for (RefListItem<Bond,int>* ri = i->bonds(); ri != NULL; ri = ri->next)
{
Atom* j = ri->item->partner(i);
conMatrix_[ i->id() - ii ] [ j->id() - ii ] = 1;
}
i = i->next;
}
// for (pb = bonds_.first(); pb != NULL; pb = pb->next)
// {
// conMatrix_[ pb->atomId(0) ] [ pb->atomId(1) ] = 1;
// conMatrix_[ pb->atomId(1) ] [ pb->atomId(0) ] = 1;
// }

// Now, transform into the connectivity matrix.
Messenger::print("transforming (full).....");
Expand Down Expand Up @@ -922,6 +925,30 @@ void Pattern::updateScaleMatrices()
Messenger::exit("Pattern::updateScaleMatrices");
}

// Return connectivity distance between atom indices specified
int Pattern::connectivity(int i, int j)
{
if (conMatrix_ == NULL)
{
Messenger::error("Connectivity matrix not yet created.\n");
return 0;
}

if ((i < 0) || (i >= nAtoms_))
{
Messenger::error("Index i for connectivity matrix is out of range (%i)\n", i);
return 0;
}

if ((j < 0) || (j >= nAtoms_))
{
Messenger::error("Index j for connectivity matrix is out of range (%i)\n", j);
return 0;
}

return conMatrix_[i][j];
}

// Validate pattern
bool Pattern::validate()
{
Expand Down Expand Up @@ -1238,7 +1265,7 @@ void Pattern::deleteAtomsFromEnd(int count)
*/

// Find rings
void Pattern::findRings()
void Pattern::findRings(int maxRingSize, int maxRings)
{
Messenger::enter("Pattern::findRings");

Expand All @@ -1254,31 +1281,64 @@ void Pattern::findRings()
if (i->nBonds() > 1)
{
// Loop over searches for different ring sizes
for (rsize=3; rsize<=prefs.maxRingSize(); rsize++)
for (rsize=3; rsize<=maxRingSize; ++rsize)
{
path.clear();
path.setRequestedSize(rsize);
// Call the recursive search to extend the path by this atom
okay = ringSearch(i,&path);
okay = ringSearch(i, &path, maxRings);
if (!okay) break;
}
}
i = i->next;
if (!okay) break;
}
if ((!okay) && (rings_.nItems() == prefs.maxRings())) Messenger::print("Maximum number of rings (%i) reached for pattern '%s'...", prefs.maxRings(), qPrintable(name_));
Messenger::print(Messenger::Verbose, "Pattern '%s' contains %i cycles of %i atoms or less.", qPrintable(name_), rings_.nItems(), prefs.maxRingSize());
if ((!okay) && (rings_.nItems() == maxRings)) Messenger::print("Maximum number of rings (%i) reached for pattern '%s'...", maxRings, qPrintable(name_));
Messenger::print(Messenger::Verbose, "Pattern '%s' contains %i cycles of %i atoms or less.", qPrintable(name_), rings_.nItems(), maxRingSize);

Messenger::exit("Pattern::findRings");
}

// Locate ring structures in the pattern from a specific atom
void Pattern::findRingsFrom(int atomIndex, int maxRingSize, int maxRings)
{
Messenger::enter("Pattern::findRings");

int n, rsize;
bool okay = true;
Atom* i;
Ring path;

// Search for rings involving the specified atom
i = firstAtom_;
for (n=0; n<atomIndex; ++n) i = i->next;

if (i->nBonds() > 1)
{
// Loop over searches for different ring sizes
for (rsize=3; rsize<=maxRingSize; ++rsize)
{
path.clear();
path.setRequestedSize(rsize);
// Call the recursive search to extend the path by this atom
okay = ringSearch(i, &path, maxRings);
if (!okay) break;
}
}

if ((!okay) && (rings_.nItems() == maxRings)) Messenger::print("Maximum number of rings (%i) reached for pattern '%s'...", maxRings, qPrintable(name_));
Messenger::print(Messenger::Verbose, "Pattern '%s' contains %i cycles of %i atoms or less.", qPrintable(name_), rings_.nItems(), maxRingSize);

Messenger::exit("Pattern::findRings");
}

// Ring search
bool Pattern::ringSearch(Atom* i, Ring *currentpath)
bool Pattern::ringSearch(Atom* i, Ring* currentpath, int maxRings)
{
// Extend the path (ring) passed by the atom 'i', searching for a path length of 'ringsize'
Messenger::enter("Pattern::ringSearch");
RefListItem<Bond,int>* bref;
Ring *r;
Ring* r;
RefListItem<Atom,int>* lastra;
bool done, maxreached = false;
// Otherwise, add it to the current path
Expand Down Expand Up @@ -1308,7 +1368,7 @@ bool Pattern::ringSearch(Atom* i, Ring *currentpath)
if (!isRingInList(currentpath))
{
// Messenger::print(Messenger::Verbose, " --- Storing current ring.");
if (rings_.nItems() == prefs.maxRings()) maxreached = true;
if (rings_.nItems() == maxRings) maxreached = true;
else
{
r = rings_.add();
Expand All @@ -1324,7 +1384,7 @@ bool Pattern::ringSearch(Atom* i, Ring *currentpath)
else
{
// Current path is not long enough, so extend it
if (!ringSearch(bref->item->partner(i),currentpath)) maxreached = true;
if (!ringSearch(bref->item->partner(i), currentpath, maxRings)) maxreached = true;
}
bref = bref->next;
if (done || maxreached) break;
Expand All @@ -1339,9 +1399,9 @@ bool Pattern::ringSearch(Atom* i, Ring *currentpath)
}

// Search existing ring list for existence of supplied ring
bool Pattern::isRingInList(Ring *source)
bool Pattern::isRingInList(Ring* source)
{
for (Ring *r = rings_.first(); r != NULL; r = r->next) if (*r == *source) return true;
for (Ring* r = rings_.first(); r != NULL; r = r->next) if (*r == *source) return true;
return false;
}

Expand Down Expand Up @@ -1516,7 +1576,7 @@ void Pattern::augment()
i = i->next;
}
// First, search for atoms in rings that have a bond order penalty
for (Ring *r = rings_.first(); r != NULL; r = r->next)
for (Ring* r = rings_.first(); r != NULL; r = r->next)
{
// Try a straight augmentation of the ring first...
for (rb = r->bonds(); rb != NULL; rb = rb->next)
Expand Down Expand Up @@ -1606,17 +1666,20 @@ void Pattern::describeAtoms()
{
// 1) Locate ring structures
Messenger::print(Messenger::Verbose, "Detecting rings in pattern '%s'...", qPrintable(name_));
findRings();
findRings(prefs.maxRingSize(), prefs.maxRings());

// 2) Reset atom environments
Messenger::print(Messenger::Verbose, "Determining atom environments in pattern '%s'...", qPrintable(name_));
clearEnvironments();
printstuff(this);

// 3) Assign hybridisation types
assignEnvironments();
printstuff(this);

// 4) Go through the ring list and see if any are aromatic
Messenger::print(Messenger::Verbose, "Assigning ring aromaticities in pattern '%s'...", qPrintable(name_));
for (Ring *r = rings_.first(); r != NULL; r = r->next) r->detectType();
for (Ring* r = rings_.first(); r != NULL; r = r->next) r->detectType();
}

// Clear environment data
Expand Down
14 changes: 9 additions & 5 deletions src/base/pattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,11 @@ class Pattern : public ListItem<Pattern>
// Create the shell of the energy expression
bool createExpression(bool vdwOnly = false, bool allowDummy = false, Forcefield* defaultForcefield = NULL);
// Create the connectivity and scaling matrices
void createMatrices();
void createMatrices(bool forceFull = false);
// Update scaling matrices
void updateScaleMatrices();
// Return connectivity distance between atom indices specified
int connectivity(int i, int j);
// Return number of bonds in one molecule of the pattern
int nBonds() const;
// Return number of angles in one molecule of the pattern
Expand Down Expand Up @@ -409,17 +411,17 @@ class Pattern : public ListItem<Pattern>
// List of rings in one molecule of the pattern
List<Ring> rings_;
// Recursive ring-search routine
bool ringSearch(Atom* i, Ring *currentpath);
bool ringSearch(Atom* i, Ring* currentpath, int maxRings);
// Search existing ring list for existence of supplied ring
bool isRingInList(Ring *source);
bool isRingInList(Ring* source);

public:
// Returns a pointer to the ring list structure
List<Ring>* ringList();
// Return number of rings in current pattern
int nRings();
// Returns the first ring in the ring list
Ring *rings();
Ring* rings();
// Returns whether atom id i is in a ring, or both atoms i and j are in the same ring
bool atomsInRing(int i, int j = -1);
// Returns whether atom id i is in a ring, or both atoms i and j are in the same ring
Expand All @@ -431,7 +433,9 @@ class Pattern : public ListItem<Pattern>
// Assign forcefield atom types
bool typeAtoms();
// Locate ring structures in the pattern
void findRings();
void findRings(int maxRingSize, int maxRings);
// Locate ring structures in the pattern from a specific atom
void findRingsFrom(int atomIndex, int maxRingSize, int maxRings);
// Augment atoms in pattern
void augment();
// Return total bond order penalty of atoms in one molecule of the pattern
Expand Down
Loading

0 comments on commit 478fddd

Please sign in to comment.