Changeset 450adf for src/Fragmentation


Ignore:
Timestamp:
Sep 12, 2016, 11:48:36 PM (8 years ago)
Author:
Frederik Heber <heber@…>
Branches:
Action_Thermostats, Add_AtomRandomPerturbation, Add_FitFragmentPartialChargesAction, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_StructOpt_integration_tests, Automaking_mpqc_open, AutomationFragmentation_failures, Candidate_v1.5.4, Candidate_v1.6.0, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, 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_ChargeSampling_PBC, Fix_ChronosMutex, Fix_FitPartialCharges, Fix_FitPotential_needs_atomicnumbers, Fix_ForceAnnealing, Fix_IndependentFragmentGrids, Fix_ParseParticles, Fix_ParseParticles_split_forward_backward_Actions, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, GeometryObjects, Gui_displays_atomic_force_velocity, IndependentFragmentGrids, IndependentFragmentGrids_IndividualZeroInstances, IndependentFragmentGrids_IntegrationTest, IndependentFragmentGrids_Sole_NN_Calculation, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, JobMarket_unresolvable_hostname_fix, ODR_violation_mpqc_open, PartialCharges_OrthogonalSummation, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, RotateToPrincipalAxisSystem_UndoRedo, SaturateAtoms_findBestMatching, StoppableMakroAction, Subpackage_CodePatterns, Subpackage_JobMarket, Subpackage_LinearAlgebra, Subpackage_levmar, Subpackage_mpqc_open, Subpackage_vmg, ThirdParty_MPQC_rebuilt_buildsystem, TrajectoryDependenant_MaxOrder, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, Ubuntu_1604_changes, stable
Children:
653cea
Parents:
2199c2
git-author:
Frederik Heber <heber@…> (06/29/14 21:20:49)
git-committer:
Frederik Heber <heber@…> (09/12/16 23:48:36)
Message:

Extracted joinPoints() function to make it accessible to tests.

  • added unit test.
  • moved some function definitions around and added documentation.
Location:
src/Fragmentation/Exporters
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • src/Fragmentation/Exporters/SphericalPointDistribution.cpp

    r2199c2 r450adf  
    6363typedef std::vector<double> DistanceArray_t;
    6464
     65// class generator: taken from www.cplusplus.com example std::generate
     66struct c_unique {
     67  int current;
     68  c_unique() {current=0;}
     69  int operator()() {return current++;}
     70} UniqueNumber;
     71
    6572inline
    6673DistanceArray_t calculatePairwiseDistances(
     
    8390}
    8491
    85 // class generator: taken from www.cplusplus.com example std::generate
    86 struct c_unique {
    87   int current;
    88   c_unique() {current=0;}
    89   int operator()() {return current++;}
    90 } UniqueNumber;
    91 
     92/** Calculate the center of a given set of points in \a _positions but only
     93 * for those indicated by \a _indices.
     94 *
     95 */
     96inline
     97Vector calculateCenter(
     98    const SphericalPointDistribution::VectorArray_t &_positions,
     99    const SphericalPointDistribution::IndexList_t &_indices)
     100{
     101  Vector Center;
     102  Center.Zero();
     103  for (SphericalPointDistribution::IndexList_t::const_iterator iter = _indices.begin();
     104      iter != _indices.end(); ++iter)
     105    Center += _positions[*iter];
     106  if (!_indices.empty())
     107    Center *= 1./(double)_indices.size();
     108
     109  return Center;
     110}
     111
     112/** Decides by an orthonormal third vector whether the sign of the rotation
     113 * angle should be negative or positive.
     114 *
     115 * \return -1 or 1
     116 */
     117inline
     118double determineSignOfRotation(
     119    const Vector &_oldPosition,
     120    const Vector &_newPosition,
     121    const Vector &_RotationAxis
     122    )
     123{
     124  Vector dreiBein(_oldPosition);
     125  dreiBein.VectorProduct(_RotationAxis);
     126  dreiBein.Normalize();
     127  const double sign =
     128      (dreiBein.ScalarProduct(_newPosition) < 0.) ? -1. : +1.;
     129  LOG(6, "DEBUG: oldCenter on plane is " << _oldPosition
     130      << ", newCenter in plane is " << _newPosition
     131      << ", and dreiBein is " << dreiBein);
     132  return sign;
     133}
     134
     135/** Convenience function to recalculate old and new center for determining plane
     136 * rotation.
     137 */
     138inline
     139void calculateOldAndNewCenters(
     140    Vector &_oldCenter,
     141    Vector &_newCenter,
     142    const SphericalPointDistribution::VectorArray_t &_referencepositions,
     143    const SphericalPointDistribution::VectorArray_t &_currentpositions,
     144    const SphericalPointDistribution::IndexList_t &_bestmatching)
     145{
     146  const size_t NumberIds = std::min(_bestmatching.size(), (size_t)3);
     147  SphericalPointDistribution::IndexList_t continuousIds(NumberIds, -1);
     148  std::generate(continuousIds.begin(), continuousIds.end(), UniqueNumber);
     149  _oldCenter = calculateCenter(_referencepositions, continuousIds);
     150  // C++11 defines a copy_n function ...
     151  SphericalPointDistribution::IndexList_t::const_iterator enditer = _bestmatching.begin();
     152  std::advance(enditer, NumberIds);
     153  SphericalPointDistribution::IndexList_t firstbestmatchingIds(NumberIds, -1);
     154  std::copy(_bestmatching.begin(), enditer, firstbestmatchingIds.begin());
     155  _newCenter = calculateCenter( _currentpositions, firstbestmatchingIds);
     156}
    92157/** Returns squared L2 error of the given \a _Matching.
    93158 *
     
    219284}
    220285
    221 /** Decides by an orthonormal third vector whether the sign of the rotation
    222  * angle should be negative or positive.
    223  *
    224  * \return -1 or 1
    225  */
    226 inline
    227 double determineSignOfRotation(
    228     const Vector &_oldPosition,
    229     const Vector &_newPosition,
    230     const Vector &_RotationAxis
    231     )
    232 {
    233   Vector dreiBein(_oldPosition);
    234   dreiBein.VectorProduct(_RotationAxis);
    235   dreiBein.Normalize();
    236   const double sign =
    237       (dreiBein.ScalarProduct(_newPosition) < 0.) ? -1. : +1.;
    238   LOG(6, "DEBUG: oldCenter on plane is " << _oldPosition
    239       << ", newCenter in plane is " << _newPosition
    240       << ", and dreiBein is " << dreiBein);
    241   return sign;
    242 }
    243 
    244286/** Finds combinatorially the best matching between points in \a _polygon
    245287 * and \a _newpolygon.
     
    247289 * We find the matching with the smallest L2 error, where we break when we stumble
    248290 * upon a matching with zero error.
     291 *
     292 * As points in \a _polygon may be have a weight greater 1 we have to match it to
     293 * multiple points in \a _newpolygon. Eventually, these multiple points are combined
     294 * for their center of weight, which is the only thing follow-up function see of
     295 * these multiple points. Hence, we actually modify \a _newpolygon in the process
     296 * such that the returned IndexList_t indicates a bijective mapping in the end.
    249297 *
    250298 * \sa recurseMatchings() for going through all matchings
     
    255303 */
    256304SphericalPointDistribution::IndexList_t SphericalPointDistribution::findBestMatching(
    257     const SphericalPointDistribution::WeightedPolygon_t &_polygon,
    258     const SphericalPointDistribution::Polygon_t &_newpolygon
     305    const WeightedPolygon_t &_polygon,
     306    Polygon_t &_newpolygon
    259307    )
    260308{
     
    280328    recurseMatchings(MCS, matching, indices, matchingsize);
    281329  }
    282   return MCS.bestmatching;
    283 }
    284 
    285 inline
    286 Vector calculateCenter(
    287     const SphericalPointDistribution::VectorArray_t &_positions,
    288     const SphericalPointDistribution::IndexList_t &_indices)
    289 {
    290   Vector Center;
    291   Center.Zero();
    292   for (SphericalPointDistribution::IndexList_t::const_iterator iter = _indices.begin();
    293       iter != _indices.end(); ++iter)
    294     Center += _positions[*iter];
    295   if (!_indices.empty())
    296     Center *= 1./(double)_indices.size();
    297 
    298   return Center;
    299 }
    300 
    301 inline
    302 void calculateOldAndNewCenters(
    303     Vector &_oldCenter,
    304     Vector &_newCenter,
    305     const SphericalPointDistribution::VectorArray_t &_referencepositions,
    306     const SphericalPointDistribution::VectorArray_t &_currentpositions,
    307     const SphericalPointDistribution::IndexList_t &_bestmatching)
    308 {
    309   const size_t NumberIds = std::min(_bestmatching.size(), (size_t)3);
    310   SphericalPointDistribution::IndexList_t continuousIds(NumberIds, -1);
    311   std::generate(continuousIds.begin(), continuousIds.end(), UniqueNumber);
    312   _oldCenter = calculateCenter(_referencepositions, continuousIds);
    313   // C++11 defines a copy_n function ...
    314   SphericalPointDistribution::IndexList_t::const_iterator enditer = _bestmatching.begin();
    315   std::advance(enditer, NumberIds);
    316   SphericalPointDistribution::IndexList_t firstbestmatchingIds(NumberIds, -1);
    317   std::copy(_bestmatching.begin(), enditer, firstbestmatchingIds.begin());
    318   _newCenter = calculateCenter( _currentpositions, firstbestmatchingIds);
     330
     331  // combine multiple points and create simple IndexList from IndexTupleList
     332  IndexTupleList_t bestmatching;
     333  for (IndexList_t::const_iterator iter = MCS.bestmatching.begin();
     334      iter != MCS.bestmatching.end(); ++iter)
     335    bestmatching.push_back(IndexList_t(1, *iter));
     336  const SphericalPointDistribution::IndexList_t IndexList =
     337      joinPoints(_newpolygon, MCS.newpoints, bestmatching);
     338
     339  return IndexList;
     340}
     341
     342SphericalPointDistribution::IndexList_t SphericalPointDistribution::joinPoints(
     343    Polygon_t &_newpolygon,
     344    const VectorArray_t &_newpoints,
     345    const IndexTupleList_t &_bestmatching
     346    )
     347{
     348  // combine all multiple points
     349  IndexList_t IndexList;
     350  IndexArray_t removalpoints;
     351  unsigned int UniqueIndex = _newpolygon.size(); // all indices up to size are used right now
     352  VectorArray_t newCenters;
     353  newCenters.reserve(_bestmatching.size());
     354  for (IndexTupleList_t::const_iterator tupleiter = _bestmatching.begin();
     355      tupleiter != _bestmatching.end(); ++tupleiter) {
     356    ASSERT (tupleiter->size() > 0,
     357        "findBestMatching() - encountered tuple in bestmatching with size 0.");
     358    if (tupleiter->size() == 1) {
     359      // add point and index
     360      IndexList.push_back(*tupleiter->begin());
     361    } else {
     362      // combine into weighted and normalized center
     363      Vector Center = calculateCenter(_newpoints, *tupleiter);
     364      Center.Normalize();
     365      _newpolygon.push_back(Center);
     366      LOG(5, "DEBUG: Combining " << tupleiter->size() << "points to weighted center "
     367          << Center << " with new index " << UniqueIndex);
     368      // mark for removal
     369      removalpoints.insert(removalpoints.end(), tupleiter->begin(), tupleiter->end());
     370      // add new index
     371      IndexList.push_back(UniqueIndex++);
     372    }
     373  }
     374  // IndexList is now our new bestmatching (that is bijective)
     375  LOG(4, "DEBUG: Our new bijective IndexList reads as " << IndexList);
     376
     377  // modifying _newpolygon: remove all points in removalpoints, add those in newCenters
     378  Polygon_t allnewpoints = _newpolygon;
     379  {
     380    _newpolygon.clear();
     381    std::sort(removalpoints.begin(), removalpoints.end());
     382    size_t i = 0;
     383    IndexArray_t::const_iterator removeiter = removalpoints.begin();
     384    for (Polygon_t::iterator iter = allnewpoints.begin();
     385        iter != allnewpoints.end(); ++iter, ++i) {
     386      if ((removeiter != removalpoints.end()) && (i == *removeiter)) {
     387        // don't add, go to next remove index
     388        ++removeiter;
     389      } else {
     390        // otherwise add points
     391        _newpolygon.push_back(*iter);
     392      }
     393    }
     394  }
     395  LOG(4, "DEBUG: The polygon with recentered points removed is " << _newpolygon);
     396
     397  // map IndexList to new shrinked _newpolygon
     398  typedef std::set<unsigned int> IndexSet_t;
     399  IndexSet_t SortedIndexList(IndexList.begin(), IndexList.end());
     400  IndexList.clear();
     401  {
     402    size_t offset = 0;
     403    IndexSet_t::const_iterator listiter = SortedIndexList.begin();
     404    IndexArray_t::const_iterator removeiter = removalpoints.begin();
     405    for (size_t i = 0; i < allnewpoints.size(); ++i) {
     406      if ((removeiter != removalpoints.end()) && (i == *removeiter)) {
     407        ++offset;
     408        ++removeiter;
     409      } else if ((listiter != SortedIndexList.end()) && (i == *listiter)) {
     410        IndexList.push_back(*listiter - offset);
     411        ++listiter;
     412      }
     413    }
     414  }
     415  LOG(4, "DEBUG: Our new bijective IndexList corrected for removed points reads as "
     416      << IndexList);
     417
     418  return IndexList;
    319419}
    320420
     
    497597SphericalPointDistribution::matchSphericalPointDistributions(
    498598    const SphericalPointDistribution::WeightedPolygon_t &_polygon,
    499     const SphericalPointDistribution::Polygon_t &_newpolygon
     599    SphericalPointDistribution::Polygon_t &_newpolygon
    500600    )
    501601{
  • src/Fragmentation/Exporters/SphericalPointDistribution.hpp

    r2199c2 r450adf  
    2121
    2222#include "LinearAlgebra/Vector.hpp"
     23
     24class SphericalPointDistributionTest;
    2325
    2426/** contains getters for the VSEPR model for specific number of electrons.
     
    7274  static Polygon_t matchSphericalPointDistributions(
    7375      const WeightedPolygon_t &_polygon,
    74       const Polygon_t &_newpolygon
     76      Polygon_t &_newpolygon
    7577      );
    7678
     
    8082  static const double SQRT_3;
    8183
     84  //!> typedef for a full rotation specification consisting of axis and angle.
    8285  typedef std::pair<Vector, double> Rotation_t;
    8386
     87  //!> typedef for a list of indices (of points in a polygon)
    8488  typedef std::list<unsigned int> IndexList_t;
     89  //!> typedef enumerating possibly multiple points accumulated as one point
     90  typedef std::list< IndexList_t > IndexTupleList_t;
     91  //!> typedef for a vector of indices
    8592  typedef std::vector<unsigned int> IndexArray_t;
     93  //!> typedef for a Vector of positions
    8694  typedef std::vector<Vector> VectorArray_t;
     95  //!> typedef for a Vector of positions with weights
     96  typedef std::vector< std::pair<Vector, int> > WeightedVectorArray_t;
    8797
    8898  //!> amplitude up to which deviations in checks of rotations are tolerated
     
    90100
    91101private:
     102  //!> grant unit tests access to private parts
     103  friend class SphericalPointDistributionTest;
     104
    92105  static std::pair<double, double> calculateErrorOfMatching(
    93106      const std::vector<Vector> &_old,
     
    116129  static IndexList_t findBestMatching(
    117130      const WeightedPolygon_t &_polygon,
    118       const Polygon_t &_newpolygon
     131      Polygon_t &_newpolygon
     132      );
     133
     134  static IndexList_t joinPoints(
     135      Polygon_t &_newpolygon,
     136      const VectorArray_t &_newpoints,
     137      const IndexTupleList_t &_bestmatching
    119138      );
    120139
  • src/Fragmentation/Exporters/unittests/SphericalPointDistributionUnitTest.cpp

    r2199c2 r450adf  
    245245}
    246246
     247/** UnitTest for joinPoints()
     248 */
     249void SphericalPointDistributionTest::joinPointsTest()
     250{
     251  // test with simple configuration of three points
     252  {
     253    SphericalPointDistribution::Polygon_t newpolygon;
     254    newpolygon += Vector(1.,0.,0.);
     255    newpolygon += Vector(0.,1.,0.);
     256    newpolygon += Vector(0.,0.,1.);
     257    SphericalPointDistribution::Polygon_t expectedpolygon = newpolygon;
     258    SphericalPointDistribution::IndexTupleList_t matching;
     259    matching += SphericalPointDistribution::IndexList_t(1,0);
     260    matching += SphericalPointDistribution::IndexList_t(1,1);
     261    matching += SphericalPointDistribution::IndexList_t(1,2);
     262    SphericalPointDistribution::IndexList_t IndexList =
     263        SphericalPointDistribution::joinPoints(
     264            newpolygon,
     265            SphericalPointDistribution::VectorArray_t(newpolygon.begin(), newpolygon.end()),
     266            matching);
     267    SphericalPointDistribution::IndexList_t expected;
     268    expected += 0,1,2;
     269    CPPUNIT_ASSERT_EQUAL( expected, IndexList );
     270    CPPUNIT_ASSERT_EQUAL( expectedpolygon, newpolygon );
     271  }
     272
     273  // test with simple configuration of three points, only two are picked
     274  {
     275    SphericalPointDistribution::Polygon_t newpolygon;
     276    newpolygon += Vector(1.,0.,0.);
     277    newpolygon += Vector(0.,1.,0.);
     278    newpolygon += Vector(0.,0.,1.);
     279    SphericalPointDistribution::Polygon_t expectedpolygon = newpolygon;
     280    SphericalPointDistribution::IndexTupleList_t matching;
     281    matching += SphericalPointDistribution::IndexList_t(1,1);
     282    matching += SphericalPointDistribution::IndexList_t(1,2);
     283    SphericalPointDistribution::IndexList_t IndexList =
     284        SphericalPointDistribution::joinPoints(
     285            newpolygon,
     286            SphericalPointDistribution::VectorArray_t(newpolygon.begin(), newpolygon.end()),
     287            matching);
     288    SphericalPointDistribution::IndexList_t expected;
     289    expected += 1,2;
     290    CPPUNIT_ASSERT_EQUAL( expected, IndexList );
     291    CPPUNIT_ASSERT_EQUAL( expectedpolygon, newpolygon );
     292  }
     293
     294  // test with simple configuration of three points, two are joined
     295  {
     296    SphericalPointDistribution::Polygon_t newpolygon;
     297    newpolygon += Vector(1.,0.,0.);
     298    newpolygon += Vector(0.,1.,0.);
     299    newpolygon += Vector(0.,0.,1.);
     300    SphericalPointDistribution::Polygon_t expectedpolygon;
     301    expectedpolygon += Vector(1.,0.,0.);
     302    expectedpolygon += Vector(0.,M_SQRT1_2,M_SQRT1_2);
     303    SphericalPointDistribution::IndexTupleList_t matching;
     304    SphericalPointDistribution::IndexList_t joined;
     305    joined += 1,2;
     306    matching += SphericalPointDistribution::IndexList_t(1,0);
     307    matching += joined;
     308    SphericalPointDistribution::IndexList_t IndexList =
     309        SphericalPointDistribution::joinPoints(
     310            newpolygon,
     311            SphericalPointDistribution::VectorArray_t(newpolygon.begin(), newpolygon.end()),
     312            matching);
     313    SphericalPointDistribution::IndexList_t expected;
     314    expected += 0,1;
     315    CPPUNIT_ASSERT_EQUAL( expected, IndexList );
     316    CPPUNIT_ASSERT_EQUAL( expectedpolygon, newpolygon );
     317  }
     318
     319  // test with simple configuration of six points, two are joined, jumbled indices
     320  {
     321    SphericalPointDistribution::Polygon_t newpolygon;
     322    newpolygon += Vector(1.,0.,1.);
     323    newpolygon += Vector(1.,0.,0.);
     324    newpolygon += Vector(1.,1.,0.);
     325    newpolygon += Vector(0.,1.,0.);
     326    newpolygon += Vector(0.,0.,1.);
     327    newpolygon += Vector(1.,0.,1.);
     328    SphericalPointDistribution::Polygon_t expectedpolygon;
     329    expectedpolygon += Vector(1.,0.,1.);
     330    expectedpolygon += Vector(1.,0.,0.);
     331    expectedpolygon += Vector(1.,1.,0.);
     332    expectedpolygon += Vector(1.,0.,1.);
     333    expectedpolygon += Vector(0.,M_SQRT1_2,M_SQRT1_2); // new centers go last
     334    SphericalPointDistribution::IndexTupleList_t matching;
     335    SphericalPointDistribution::IndexList_t joined;
     336    joined += 3,4;
     337    matching += SphericalPointDistribution::IndexList_t(1,1);
     338    matching += joined;
     339    SphericalPointDistribution::IndexList_t IndexList =
     340        SphericalPointDistribution::joinPoints(
     341            newpolygon,
     342            SphericalPointDistribution::VectorArray_t(newpolygon.begin(), newpolygon.end()),
     343            matching);
     344    SphericalPointDistribution::IndexList_t expected;
     345    expected += 1,4;
     346    CPPUNIT_ASSERT_EQUAL( expected, IndexList );
     347    CPPUNIT_ASSERT_EQUAL( expectedpolygon, newpolygon );
     348  }
     349}
    247350
    248351/** UnitTest for matchSphericalPointDistributions() with three points
  • src/Fragmentation/Exporters/unittests/SphericalPointDistributionUnitTest.hpp

    r2199c2 r450adf  
    2323    CPPUNIT_TEST_SUITE( SphericalPointDistributionTest) ;
    2424    CPPUNIT_TEST ( areEqualToWithinBoundsTest );
     25    CPPUNIT_TEST ( joinPointsTest );
    2526    CPPUNIT_TEST ( matchSphericalPointDistributionsTest_2 );
    2627    CPPUNIT_TEST ( matchSphericalPointDistributionsTest_3 );
     
    3637      void tearDown();
    3738      void areEqualToWithinBoundsTest();
     39      void joinPointsTest();
    3840      void matchSphericalPointDistributionsTest_2();
    3941      void matchSphericalPointDistributionsTest_3();
Note: See TracChangeset for help on using the changeset viewer.