Changeset 3b74fa for src/Actions


Ignore:
Timestamp:
Jul 12, 2017, 7:10:31 PM (7 years ago)
Author:
Frederik Heber <frederik.heber@…>
Branches:
Action_Thermostats, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_StructOpt_integration_tests, AutomationFragmentation_failures, Candidate_v1.6.1, ChemicalSpaceEvaluator, Enhanced_StructuralOptimization, Enhanced_StructuralOptimization_continued, Exclude_Hydrogens_annealWithBondGraph, Fix_Verbose_Codepatterns, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, Gui_displays_atomic_force_velocity, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, PythonUI_with_named_parameters, Recreated_GuiChecks, StoppableMakroAction, TremoloParser_IncreasedPrecision
Children:
d24ef58
Parents:
0716eac
git-author:
Frederik Heber <frederik.heber@…> (05/14/17 21:08:41)
git-committer:
Frederik Heber <frederik.heber@…> (07/12/17 19:10:31)
Message:

Rewrite of StretchBondAction to take bondgraph into account.

  • i.e. we now look at the bond graph of the molecule to find all atoms on either side of the bond and shift each set accordingly.
  • this functionality needs to be refactored into a distinct class lateron.
  • TESTS: Added new test case on cyclic bond with benzene.
Location:
src/Actions/MoleculeAction
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • src/Actions/MoleculeAction/StretchBondAction.cpp

    r0716eac r3b74fa  
    3333#endif
    3434
     35#include <boost/graph/adjacency_list.hpp>
     36#include <boost/graph/breadth_first_search.hpp>
     37#include <boost/graph/subgraph.hpp>
     38
    3539//#include "CodePatterns/MemDebug.hpp"
    3640
     
    4448#include "Atom/atom.hpp"
    4549#include "Bond/bond.hpp"
     50#include "Descriptors/AtomIdDescriptor.hpp"
    4651#include "molecule.hpp"
    4752#include "World.hpp"
     
    5257#include "StretchBondAction.def"
    5358#include "Action_impl_pre.hpp"
     59
     60
     61/**
     62 * I have no idea why this is so complicated with BGL ...
     63 *
     64 * This is taken from the book "The Boost Graph Library: User Guide and Reference Manual, Portable Documents",
     65 * chapter "Basic Graph Algorithms", example on calculating the bacon number.
     66 */
     67template <typename DistanceMap>
     68class distance_recorder : public boost::default_bfs_visitor
     69{
     70public:
     71  distance_recorder(DistanceMap dist) : d(dist) {}
     72
     73  template <typename Edge, typename Graph>
     74  void tree_edge(Edge e, const Graph &g) const {
     75    typename boost::graph_traits<Graph>::vertex_descriptor u = source(e,g), v = target(e,g);
     76    d[v] = d[u] + 1;
     77  }
     78
     79private:
     80  DistanceMap d;
     81};
     82
     83template <typename DistanceMap>
     84distance_recorder<DistanceMap> record_distance(DistanceMap d)
     85{
     86  return distance_recorder<DistanceMap>(d);
     87}
     88
    5489/** =========== define the function ====================== */
    5590ActionState::ptr MoleculeStretchBondAction::performCall()
     
    6196    return Action::failure;
    6297  }
     98  std::vector<atomId_t> atomids(2);
     99  atomids[0] = atoms[0]->getId();
     100  atomids[1] = atoms[1]->getId();
     101  std::sort(atomids.begin(), atomids.end());
     102  LOG(1, "DEBUG: Selected nodes are " << atomids);
    63103  molecule *mol = World::getInstance().
    64104      getMolecule(MoleculeById(atoms[0]->getMolecule()->getId()));
     
    72112  LOG(1, "INFO: Old bond distance is " << olddistance << ", stretching to " << newdistance << ".");
    73113
    74   // create the bond plane and mid-distance
     114  // Assume the selected bond splits the molecule into two parts, each one on
     115  // either side of the bond. We need to perform a BFS from each bond partner
     116  // not using the selected bond. Therefrom, we obtain two sets of atoms/nodes.
     117  // If both are disjoint, the bond is not contained in a cycle and we simply
     118  // shift either set as desired. If not, then we simply shift each atom,
     119  // leaving the other positions untouched.
     120  typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS,
     121      boost::no_property, boost::no_property > UndirectedGraph;
     122
     123  // convert BondGraph into boost::graph
     124  UndirectedGraph molgraph(mol->getAtomCount());
     125  size_t no_edges = 0;
     126  for(molecule::const_iterator iter = const_cast<const molecule * const>(mol)->begin();
     127      iter != const_cast<const molecule * const>(mol)->end(); ++iter) {
     128    LOG(2, "DEBUG: Looking at node " << (*iter)->getId());
     129    const BondList& ListOfBonds = (*iter)->getListOfBonds();
     130    for(BondList::const_iterator bonditer = ListOfBonds.begin();
     131        bonditer != ListOfBonds.end(); ++bonditer) {
     132      const unsigned int &leftid = (*bonditer)->leftatom->getId();
     133      const unsigned int &rightid = (*bonditer)->rightatom->getId();
     134      // only add each edge once and do not add selected edge
     135      if ((leftid == (*iter)->getId())
     136          && ((leftid != atomids[0]) || (rightid != atomids[1]))) {
     137        LOG(1, "DEBUG: ADDING edge " << leftid << " <-> " << rightid);
     138        boost::add_edge(leftid, rightid, molgraph);
     139        ++no_edges;
     140      } else {
     141        LOG(1, "DEBUG: Discarding edge " << leftid << " <-> " << rightid);
     142      }
     143    }
     144  }
     145  typedef boost::property_map < boost::adjacency_list <>, boost::vertex_index_t >::type index_map_t;
     146  index_map_t index_map = boost::get(boost::vertex_index, molgraph);
     147  const size_t num_vertices = boost::num_vertices(molgraph);
     148  LOG(2, "DEBUG: We have " << num_vertices << " nodes and " << no_edges
     149      << " edges in the molecule graph.");
     150
     151  std::vector< std::vector<size_t> > distances;
     152  for (size_t i=0;i<2;++i) {
     153    distances.push_back(std::vector<size_t>(num_vertices, num_vertices+1)); // set distance to num+1
     154    distances[i][atomids[i]] = 0;
     155    boost::breadth_first_search(
     156        molgraph,
     157        boost::vertex(atomids[i], molgraph),
     158        boost::visitor(record_distance(&(distances[i][0]))));
     159    LOG(3, "DEBUG: From atom #" << atomids[i]
     160        << " BFS discovered the following distances " << distances[i]);
     161  }
     162
    75163  const Vector NormalVector = (atoms[0]->getPosition() - atoms[1]->getPosition())* (1./olddistance);
    76   const Vector OffsetVector = 0.5*(atoms[0]->getPosition() + atoms[1]->getPosition());
    77   Plane bondplane(NormalVector, OffsetVector);
    78   // go through the molecule and stretch each atom relative two plane
    79164  const double shift = 0.5*(newdistance - olddistance);
    80   const Vector PositiveShift = shift * NormalVector;
    81   const Vector NegativeShift = -shift * NormalVector;
     165  std::vector<Vector> Shift(2);
     166  Shift[0] = shift * NormalVector;
     167  Shift[1] = -shift * NormalVector;
    82168  Box &domain = World::getInstance().getDomain();
    83   for (molecule::iterator iter = mol->begin(); iter != mol->end(); ++iter) {
    84     const Vector &position = (*iter)->getPosition();
    85     // for each atom determine on which side of plane it is and shift accordingly
    86     if (bondplane.SignedDistance(position) > 0) {
    87       (*iter)->setPosition( domain.enforceBoundaryConditions(position+PositiveShift) );
    88     } else {
    89       (*iter)->setPosition( domain.enforceBoundaryConditions(position+NegativeShift) );
    90     }
    91   }
    92 
    93   MoleculeStretchBondState *UndoState = new MoleculeStretchBondState(shift, bondplane, mol, params);
     169  std::vector< std::vector<size_t> > bondside_sets(2);
     170
     171  // Check whether there are common nodes in each set of distances
     172  for (size_t i=0;i<num_vertices;++i)
     173    if ((distances[0][i] != (num_vertices+1)) && (distances[1][i] != (num_vertices+1))) {
     174      ELOG(2, "Node #" << i << " is reachable from either side of bond, hence must by cyclic."
     175          << " Shifting only bond partners.");
     176      for(size_t j=0;j<2;++j) {
     177        bondside_sets[j].push_back(atoms[j]->getId());
     178        const Vector &position = atoms[j]->getPosition();
     179        atoms[j]->setPosition( domain.enforceBoundaryConditions(position+Shift[j]) );
     180      }
     181      break;
     182    }
     183
     184  // go through the molecule and stretch each atom in either set of nodes
     185  if (bondside_sets[0].empty()) {
     186    for (molecule::iterator iter = mol->begin(); iter != mol->end(); ++iter) {
     187      const Vector &position = (*iter)->getPosition();
     188      // for each atom determine in which set of nodes it is and shift accordingly
     189      size_t i=0;
     190      const size_t nodeindex = boost::get(index_map, boost::vertex((*iter)->getId(), molgraph));
     191      for (;i<2;++i) {
     192        if (distances[i][nodeindex] != (num_vertices+1)) {
     193          (*iter)->setPosition( domain.enforceBoundaryConditions(position+Shift[i]) );
     194          bondside_sets[i].push_back((*iter)->getId());
     195          break;
     196        }
     197      }
     198      if (i==2) {
     199        ELOG(1, "Atom " << *iter << " is not contained on either side of bond? Undoing done shifts");
     200        // Have to undo shifts
     201        for (i=0;i<2;++i) {
     202          for (std::vector<size_t>::const_iterator iter = bondside_sets[i].begin();
     203              iter != bondside_sets[i].end(); ++iter) {
     204            atom &walker = *World::getInstance().getAtom(AtomById(*iter));
     205            const Vector &position = walker.getPosition();
     206            walker.setPosition( domain.enforceBoundaryConditions(position-Shift[i]) );
     207          }
     208        }
     209        return Action::failure;
     210      }
     211    }
     212  }
     213
     214  MoleculeStretchBondState *UndoState = new MoleculeStretchBondState(Shift, bondside_sets, mol, params);
    94215  return ActionState::ptr(UndoState);
    95216}
     
    99220
    100221  // use given plane to undo
    101   const Vector PositiveShift = state->shift * state->bondplane.getNormal();
    102   const Vector NegativeShift = -state->shift * state->bondplane.getNormal();
    103222  Box &domain = World::getInstance().getDomain();
    104   molecule *mol = World::getInstance().
    105       getMolecule(MoleculeById(state->mol->getId()));
    106   for (molecule::iterator iter = mol->begin();
    107       iter != mol->end(); ++iter) {
    108     const Vector &position = (*iter)->getPosition();
    109     // for each atom determine on which side of plane it is and shift accordingly
    110     if (state->bondplane.SignedDistance(position) < 0) {
    111       (*iter)->setPosition( domain.enforceBoundaryConditions(position+PositiveShift) );
    112     } else {
    113       (*iter)->setPosition( domain.enforceBoundaryConditions(position+NegativeShift) );
     223  for (size_t i=0;i<2;++i) {
     224    for (std::vector<size_t>::const_iterator iter = state->bondside_sets[i].begin();
     225        iter != state->bondside_sets[i].end(); ++iter) {
     226      atom &walker = *World::getInstance().getAtom(AtomById(*iter));
     227      const Vector &position = walker.getPosition();
     228      walker.setPosition( domain.enforceBoundaryConditions(position-state->Shift[i]) );
    114229    }
    115230  }
     
    121236  MoleculeStretchBondState *state = assert_cast<MoleculeStretchBondState*>(_state.get());
    122237
    123   // use given plane to undo
    124   const Vector PositiveShift = state->shift * state->bondplane.getNormal();
    125   const Vector NegativeShift = -state->shift * state->bondplane.getNormal();
    126238  Box &domain = World::getInstance().getDomain();
    127   molecule *mol = World::getInstance().
    128       getMolecule(MoleculeById(state->mol->getId()));
    129   for (molecule::iterator iter = mol->begin();
    130       iter != mol->end(); ++iter) {
    131     const Vector &position = (*iter)->getPosition();
    132     // for each atom determine on which side of plane it is and shift accordingly
    133     if (state->bondplane.SignedDistance(position) > 0) {
    134       (*iter)->setPosition( domain.enforceBoundaryConditions(position+PositiveShift) );
    135     } else {
    136       (*iter)->setPosition( domain.enforceBoundaryConditions(position+NegativeShift) );
    137     }
    138   }
     239  for (size_t i=0;i<2;++i) {
     240    for (std::vector<size_t>::const_iterator iter = state->bondside_sets[i].begin();
     241        iter != state->bondside_sets[i].end(); ++iter) {
     242      atom &walker = *World::getInstance().getAtom(AtomById(*iter));
     243      const Vector &position = walker.getPosition();
     244      walker.setPosition( domain.enforceBoundaryConditions(position+state->Shift[i]) );
     245    }
     246  }
     247
    139248  return ActionState::ptr(_state);
    140249}
  • src/Actions/MoleculeAction/StretchBondAction.def

    r0716eac r3b74fa  
    2121(RangeValidator< double >(0., 10.))
    2222
    23 #define statetypes (const double)(const Plane)(const molecule *)
    24 #define statereferences (shift)(bondplane)(mol)
     23#define statetypes (std::vector<Vector>)(std::vector< std::vector<size_t> >)(const molecule *)
     24#define statereferences (Shift)(bondside_sets)(mol)
    2525
    2626// some defines for all the names, you may use ACTION, STATE and PARAMS
Note: See TracChangeset for help on using the changeset viewer.