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.
File:
1 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{
Note: See TracChangeset for help on using the changeset viewer.