Ignore:
Timestamp:
Apr 18, 2013, 4:23:26 PM (12 years ago)
Author:
Frederik Heber <heber@…>
Branches:
Action_Thermostats, Add_AtomRandomPerturbation, Add_FitFragmentPartialChargesAction, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Added_ParseSaveFragmentResults, AddingActions_SaveParseParticleParameters, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_ParticleName_to_Atom, Adding_StructOpt_integration_tests, AtomFragments, Automaking_mpqc_open, AutomationFragmentation_failures, Candidate_v1.5.4, Candidate_v1.6.0, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, CombiningParticlePotentialParsing, Combining_Subpackages, Debian_Package_split, Debian_package_split_molecuildergui_only, Disabling_MemDebug, Docu_Python_wait, EmpiricalPotential_contain_HomologyGraph, EmpiricalPotential_contain_HomologyGraph_documentation, Enable_parallel_make_install, Enhance_userguide, Enhanced_StructuralOptimization, Enhanced_StructuralOptimization_continued, Example_ManyWaysToTranslateAtom, Exclude_Hydrogens_annealWithBondGraph, FitPartialCharges_GlobalError, Fix_BoundInBox_CenterInBox_MoleculeActions, Fix_ChargeSampling_PBC, Fix_ChronosMutex, Fix_FitPartialCharges, Fix_FitPotential_needs_atomicnumbers, Fix_ForceAnnealing, Fix_IndependentFragmentGrids, Fix_ParseParticles, Fix_ParseParticles_split_forward_backward_Actions, Fix_PopActions, Fix_QtFragmentList_sorted_selection, Fix_Restrictedkeyset_FragmentMolecule, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, Fix_fitting_potentials, Fixes, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, FragmentAction_writes_AtomFragments, FragmentMolecule_checks_bonddegrees, GeometryObjects, Gui_Fixes, Gui_displays_atomic_force_velocity, ImplicitCharges, IndependentFragmentGrids, IndependentFragmentGrids_IndividualZeroInstances, IndependentFragmentGrids_IntegrationTest, IndependentFragmentGrids_Sole_NN_Calculation, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, JobMarket_unresolvable_hostname_fix, MoreRobust_FragmentAutomation, ODR_violation_mpqc_open, PartialCharges_OrthogonalSummation, PdbParser_setsAtomName, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, Rewrite_FitPartialCharges, RotateToPrincipalAxisSystem_UndoRedo, SaturateAtoms_findBestMatching, SaturateAtoms_singleDegree, StoppableMakroAction, Subpackage_CodePatterns, Subpackage_JobMarket, Subpackage_LinearAlgebra, Subpackage_levmar, Subpackage_mpqc_open, Subpackage_vmg, Switchable_LogView, ThirdParty_MPQC_rebuilt_buildsystem, TrajectoryDependenant_MaxOrder, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, TremoloParser_setsAtomName, Ubuntu_1604_changes, stable
Children:
53c579
Parents:
326000
git-author:
Frederik Heber <heber@…> (03/21/13 09:33:31)
git-committer:
Frederik Heber <heber@…> (04/18/13 16:23:26)
Message:

Using boost::graph to obtain maximum matching for bond degree correction.

  • added bimap to boost.m4, added boost_bimap and boost_graph to configure.ac.
  • rewrote createMatching() in BondGraph with boost::graph, code mostly taken from maximum cardinality matching example.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Graph/BondGraph.cpp

    r326000 r4f04ab8  
    3333#endif
    3434
     35// boost::graph uses placement new
     36#include <boost/graph/adjacency_list.hpp>
     37
    3538#include "CodePatterns/MemDebug.hpp"
    3639
     40#include <algorithm>
     41#include <boost/bimap.hpp>
     42#include <boost/bind.hpp>
     43#include <boost/foreach.hpp>
     44#include <boost/function.hpp>
     45#include <boost/graph/max_cardinality_matching.hpp>
    3746#include <deque>
    3847#include <iostream>
     
    320329  return treeedges;
    321330}
     331
     332struct hasDelta {
     333  bool operator()(atom *_atom) {
     334    const double delta =
     335        _atom->getType()->getNoValenceOrbitals() - _atom->CountBonds();
     336    return (fabs(delta) > 0);
     337  }
     338};
     339
     340typedef std::set<atom *> deltaatoms_t;
     341typedef std::set<bond::ptr> deltaedges_t;
     342
     343static int gatherAllDeltaAtoms(
     344    const deltaatoms_t &allatoms,
     345    deltaatoms_t &deltaatoms)
     346{
     347  static hasDelta delta;
     348  deltaatoms.clear();
     349  for (deltaatoms_t::const_iterator iter = allatoms.begin();
     350      iter != allatoms.end(); ++iter) {
     351    if (delta(*iter))
     352      deltaatoms.insert(*iter);
     353  }
     354  return deltaatoms.size();
     355}
     356
     357typedef boost::bimap<int,atom*> AtomIndexLookup_t;
     358
     359static AtomIndexLookup_t createAtomIndexLookup(
     360    const deltaedges_t &edges)
     361{
     362  AtomIndexLookup_t AtomIndexLookup;
     363  size_t index = 0;
     364  for (deltaedges_t::const_iterator edgeiter = edges.begin();
     365      edgeiter != edges.end(); ++edgeiter) {
     366    const bond::ptr & _bond = *edgeiter;
     367
     368    // insert left into lookup
     369    std::pair< AtomIndexLookup_t::iterator, bool > inserter =
     370        AtomIndexLookup.insert( AtomIndexLookup_t::value_type(index, _bond->leftatom) );
     371    if (inserter.second)
     372      ++index;
     373
     374    // insert right into lookup
     375    inserter = AtomIndexLookup.insert( AtomIndexLookup_t::value_type(index, _bond->rightatom) );
     376    if (inserter.second)
     377      ++index;
     378  }
     379  return AtomIndexLookup;
     380}
     381
     382typedef std::map< std::pair<atom *, atom*>, bond::ptr> BondLookup_t;
     383static BondLookup_t createBondLookup(
     384    const deltaedges_t &edges)
     385{
     386  BondLookup_t BondLookup;
     387  for (deltaedges_t::const_iterator edgeiter = edges.begin();
     388      edgeiter != edges.end(); ++edgeiter) {
     389    const bond::ptr & _bond = *edgeiter;
     390
     391    // insert bond into pair lookup
     392    BondLookup.insert(
     393        std::make_pair(
     394            std::make_pair(_bond->leftatom, _bond->rightatom),
     395            _bond)
     396    );
     397  }
     398  return BondLookup;
     399}
     400
     401typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> graph_t;
     402typedef std::vector<boost::graph_traits<graph_t>::vertex_descriptor> mate_t;
     403
     404static void fillEdgesIntoMatching(
     405    graph_t &g,
     406    mate_t &mate,
     407    const AtomIndexLookup_t &AtomIndexLookup,
     408    const BondLookup_t &BondLookup,
     409    deltaedges_t &matching
     410    )
     411{
     412  matching.clear();
     413  boost::graph_traits<graph_t>::vertex_iterator vi, vi_end;
     414  for(tie(vi,vi_end) = boost::vertices(g); vi != vi_end; ++vi)
     415    if (mate[*vi] != boost::graph_traits<graph_t>::null_vertex() && *vi < mate[*vi]) {
     416      atom * leftatom = AtomIndexLookup.left.at(*vi);
     417      atom * rightatom = AtomIndexLookup.left.at(mate[*vi]);
     418      std::pair<atom *,atom *> AtomPair(leftatom, rightatom);
     419      std::pair<atom *,atom *> reverseAtomPair(rightatom, leftatom);
     420      BondLookup_t::const_iterator iter = BondLookup.find(AtomPair);
     421      if (iter != BondLookup.end()) {
     422        matching.insert(iter->second);
     423      } else {
     424        iter = BondLookup.find(reverseAtomPair);
     425        if (iter != BondLookup.end()) {
     426          matching.insert(iter->second);
     427        } else
     428          ASSERT(0, "fillEdgesIntoMatching() - cannot find ("+toString(*vi)+","
     429              +toString(mate[*vi])+") in BondLookup.");
     430      }
     431    }
     432}
     433
     434static bool createMatching(
     435    deltaedges_t &deltaedges,
     436    deltaedges_t &matching
     437    )
     438{
     439  // gather all vertices for graph in a lookup structure
     440  // to translate the graphs indices to atoms and also to associated bonds
     441  AtomIndexLookup_t AtomIndexLookup = createAtomIndexLookup(deltaedges);
     442  BondLookup_t BondLookup = createBondLookup(deltaedges);
     443  const int n_vertices = AtomIndexLookup.size();
     444
     445  // construct graph
     446  graph_t g(n_vertices);
     447
     448  // add edges to graph
     449  for (deltaedges_t::const_iterator edgeiter = deltaedges.begin();
     450      edgeiter != deltaedges.end(); ++edgeiter) {
     451    const bond::ptr & _bond = *edgeiter;
     452    boost::add_edge(
     453        AtomIndexLookup.right.at(_bond->leftatom),
     454        AtomIndexLookup.right.at(_bond->rightatom),
     455        g);
     456  }
     457
     458  // mate structure contains unique edge partner to every vertex in matching
     459  mate_t mate(n_vertices);
     460
     461  // get maximum matching over given edges
     462  bool success = boost::checked_edmonds_maximum_cardinality_matching(g, &mate[0]);
     463
     464  if (success) {
     465    LOG(1, "STATUS: Found a matching of size " << matching_size(g, &mate[0]) << ".");
     466    fillEdgesIntoMatching(g, mate, AtomIndexLookup, BondLookup, matching);
     467  } else {
     468    ELOG(2, "Failed to find maximum matching.");
     469  }
     470
     471  return success;
     472}
     473
     474
     475int BondGraph::calculateBondDegree(const deltaatoms_t &allatoms) const
     476{
     477  deltaatoms_t deltaatoms;
     478  deltaedges_t deltaedges;
     479  deltaedges_t matching;
     480
     481  LOG(1, "STATUS: Calculating bond degrees.");
     482  if (DoLog(2)) {
     483    std::stringstream output;
     484    output << "INFO: All atoms are: ";
     485    BOOST_FOREACH( atom *_atom, allatoms) {
     486      output << *_atom << " ";
     487    }
     488    LOG(2, output.str());
     489  }
     490
     491  size_t IterCount = 0;
     492  // 1. gather all atoms with delta > 0
     493  while ((gatherAllDeltaAtoms(allatoms, deltaatoms) != 0) && (IterCount < 100)) {
     494    if (DoLog(3)) {
     495      std::stringstream output;
     496      output << "DEBUG: Current delta atoms are: ";
     497      BOOST_FOREACH( atom *_atom, deltaatoms) {
     498        output << *_atom << " ";
     499      }
     500      LOG(3, output.str());
     501    }
     502
     503    // 2. gather all edges that connect atoms with both(!) having delta > 0
     504    deltaedges.clear();
     505    for (deltaatoms_t::const_iterator atomiter = deltaatoms.begin();
     506        atomiter != deltaatoms.end(); ++atomiter) {
     507      const atom * const _atom = *atomiter;
     508      const BondList& ListOfBonds = (*atomiter)->getListOfBonds();
     509      for (BondList::const_iterator bonditer = ListOfBonds.begin();
     510          bonditer != ListOfBonds.end();++bonditer) {
     511        const bond::ptr _bond = *bonditer;
     512        if ((_bond->leftatom == _atom) && (deltaatoms.find(_bond->rightatom) != deltaatoms.end()))
     513          deltaedges.insert(_bond);
     514        else if ((_bond->rightatom == _atom) && (deltaatoms.find(_bond->leftatom) != deltaatoms.end()))
     515          deltaedges.insert(_bond);
     516      }
     517    }
     518    if (DoLog(3)) {
     519      std::stringstream output;
     520      output << "DEBUG: Current delta bonds are: ";
     521      BOOST_FOREACH( bond::ptr _bond, deltaedges) {
     522        output << *_bond << " ";
     523      }
     524      LOG(3, output.str());
     525    }
     526    if (deltaedges.empty())
     527      break;
     528
     529    // 3. build matching over these edges
     530    if (!createMatching(deltaedges, matching))
     531      break;
     532    if (DoLog(2)) {
     533      std::stringstream output;
     534      output << "DEBUG: Resulting matching is: ";
     535      BOOST_FOREACH( bond::ptr _bond, matching) {
     536        output << *_bond << " ";
     537      }
     538      LOG(2, output.str());
     539    }
     540
     541    // 4. increase degree for each edge of the matching
     542    LOG(2, "DEBUG: Increasing bond degrees by one.");
     543    for (deltaedges_t::iterator edgeiter = matching.begin();
     544        edgeiter != matching.end(); ++edgeiter) {
     545      (*edgeiter)->setDegree( (*edgeiter)->getDegree()+1 );
     546    }
     547
     548    // 6. stop after a given number of iterations or when all atoms are happy.
     549    ++IterCount;
     550  };
     551
     552  // check whether we still have deltaatoms
     553  {
     554    hasDelta delta;
     555    for (deltaatoms_t::const_iterator iter = allatoms.begin();
     556        iter != allatoms.end(); ++iter)
     557      if (delta(*iter))
     558        ELOG(2, "Could not find satisfy charge neutrality for atom " << **iter << ".");
     559  }
     560
     561  return deltaedges.size();
     562}
Note: See TracChangeset for help on using the changeset viewer.