Changeset 64cafb2 for src


Ignore:
Timestamp:
Sep 10, 2016, 4:01:20 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, Fixes, 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, SaturateAtoms_singleDegree, 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:
0c42f2, cdac1d
Parents:
d32f60
git-author:
Frederik Heber <heber@…> (05/10/16 18:33:50)
git-committer:
Frederik Heber <heber@…> (09/10/16 16:01:20)
Message:

Revert "Trimmed down SphericalPointDistribution to what is needed at the moment."

This reverts commit 0241c59e7f10c73f87336715af0aadac2b2d4db1.

Location:
src
Files:
2 added
4 edited

Legend:

Unmodified
Added
Removed
  • src/Actions/AtomAction/SaturateAction.cpp

    rd32f60 r64cafb2  
    7777        "ChangeElementAction::performCall() - mol is still NULL." );
    7878
    79     // add the hydrogens
    80     const Vector AtomsPosition = _atom->getPosition();
    81     double typical_distance = _atom->getType()->getHBondDistance(0);
    82     if (typical_distance == -1.)
    83       typical_distance = 1.;
    84     SphericalPointDistribution PointSphere(typical_distance);
    85     PointSphere.initSelf(_atom->getType()->getNoValenceOrbitals());
    86     for (SphericalPointDistribution::Polygon_t::const_iterator iter = PointSphere.points.begin();
    87         iter != PointSphere.points.end(); ++iter) {
    88       // for every Vector add a point relative to atom's position
    89       atom * hydrogenAtom = World::getInstance().createAtom();
    90       hydrogenAtom->setType(hydrogen);
    91       hydrogenAtom->setPosition(AtomsPosition + *iter);
    92       mol->AddAtom(hydrogenAtom);
    93       // add bond
    94       _atom->addBond(WorldTime::getTime(), hydrogenAtom);
    95       // mark down for undo state
    96       addedHydrogens.push_back(AtomicInfo(*(hydrogenAtom)));
    97     }
     79//    // add the hydrogens
     80//    const Vector AtomsPosition = _atom->getPosition();
     81//    double typical_distance = _atom->getType()->getHBondDistance(0);
     82//    if (typical_distance == -1.)
     83//      typical_distance = 1.;
     84//    SphericalPointDistribution PointSphere(typical_distance);
     85//    PointSphere.initSelf(_atom->getType()->getNoValenceOrbitals());
     86//    for (SphericalPointDistribution::Polygon_t::const_iterator iter = PointSphere.points.begin();
     87//        iter != PointSphere.points.end(); ++iter) {
     88//      // for every Vector add a point relative to atom's position
     89//      atom * hydrogenAtom = World::getInstance().createAtom();
     90//      hydrogenAtom->setType(hydrogen);
     91//      hydrogenAtom->setPosition(AtomsPosition + *iter);
     92//      mol->AddAtom(hydrogenAtom);
     93//      // add bond
     94//      _atom->addBond(WorldTime::getTime(), hydrogenAtom);
     95//      // mark down for undo state
     96//      addedHydrogens.push_back(AtomicInfo(*(hydrogenAtom)));
     97//    }
    9898  }
    9999
  • src/Fragmentation/Exporters/SphericalPointDistribution.cpp

    rd32f60 r64cafb2  
    3838
    3939#include "CodePatterns/Assert.hpp"
    40 #include "CodePatterns/Log.hpp"
     40#include "CodePatterns/IteratorAdaptors.hpp"
     41#include "CodePatterns/toString.hpp"
    4142
    4243#include <algorithm>
     44#include <cmath>
     45#include <limits>
     46#include <list>
    4347#include <vector>
     48#include <map>
    4449
    4550#include "LinearAlgebra/Line.hpp"
     
    4752#include "LinearAlgebra/Vector.hpp"
    4853
    49 void SphericalPointDistribution::initSelf(const int _NumberOfPoints)
    50 {
    51   switch (_NumberOfPoints)
    52   {
    53     case 0:
    54       points = get<0>();
    55       break;
    56     case 1:
    57       points = get<1>();
    58       break;
    59     case 2:
    60       points = get<2>();
    61       break;
    62     case 3:
    63       points = get<3>();
    64       break;
    65     case 4:
    66       points = get<4>();
    67       break;
    68     case 5:
    69       points = get<5>();
    70       break;
    71     case 6:
    72       points = get<6>();
    73       break;
    74     case 7:
    75       points = get<7>();
    76       break;
    77     case 8:
    78       points = get<8>();
    79       break;
    80     case 9:
    81       points = get<9>();
    82       break;
    83     case 10:
    84       points = get<10>();
    85       break;
    86     case 11:
    87       points = get<11>();
    88       break;
    89     case 12:
    90       points = get<12>();
    91       break;
    92     case 14:
    93       points = get<14>();
    94       break;
    95     default:
    96       ASSERT(0, "SphericalPointDistribution::initSelf() - cannot deal with the case "
    97           +toString(_NumberOfPoints)+".");
    98   }
    99   LOG(3, "DEBUG: Ideal polygon is " << points);
    100 }
    101 
     54typedef std::list<unsigned int> IndexList_t;
     55typedef std::vector<unsigned int> IndexArray_t;
     56typedef std::vector<Vector> VectorArray_t;
     57typedef std::vector<double> DistanceArray_t;
     58
     59DistanceArray_t calculatePairwiseDistances(
     60    const std::vector<Vector> &_points,
     61    const IndexList_t &_indices
     62    )
     63{
     64  DistanceArray_t result;
     65  for (IndexList_t::const_iterator firstiter = _indices.begin();
     66      firstiter != _indices.end(); ++firstiter) {
     67    for (IndexList_t::const_iterator seconditer = firstiter;
     68        seconditer != _indices.end(); ++seconditer) {
     69      if (firstiter == seconditer)
     70        continue;
     71      const double distance = (_points[*firstiter] - _points[*seconditer]).NormSquared();
     72      result.push_back(distance);
     73    }
     74  }
     75  return result;
     76}
     77
     78// class generator: taken from www.cplusplus.com example std::generate
     79struct c_unique {
     80  int current;
     81  c_unique() {current=0;}
     82  int operator()() {return ++current;}
     83} UniqueNumber;
     84
     85/** Returns squared L2 error of the given \a _Matching.
     86 *
     87 * We compare the pair-wise distances of each associated matching
     88 * and check whether these distances each match between \a _old and
     89 * \a _new.
     90 *
     91 * \param _old first set of points (fewer or equal to \a _new)
     92 * \param _new second set of points
     93 * \param _Matching matching between the two sets
     94 * \return pair with L1 and squared L2 error
     95 */
     96std::pair<double, double> calculateErrorOfMatching(
     97    const std::vector<Vector> &_old,
     98    const std::vector<Vector> &_new,
     99    const IndexList_t &_Matching)
     100{
     101  std::pair<double, double> errors( std::make_pair( 0., 0. ) );
     102
     103  if (_Matching.size() > 1) {
     104    // convert matching into two vectors to calculate distance among another
     105
     106    // calculate all pair-wise distances
     107    IndexList_t keys(_Matching.size());
     108    std::generate (keys.begin(), keys.end(), UniqueNumber);
     109    const DistanceArray_t firstdistances = calculatePairwiseDistances(_old, keys);
     110    const DistanceArray_t seconddistances = calculatePairwiseDistances(_new, _Matching);
     111
     112    ASSERT( firstdistances.size() == seconddistances.size(),
     113        "calculateL2ErrorOfMatching() - mismatch in pair-wise distance array sizes.");
     114    DistanceArray_t::const_iterator firstiter = firstdistances.begin();
     115    DistanceArray_t::const_iterator seconditer = seconddistances.begin();
     116    for (;(firstiter != firstdistances.end()) && (seconditer != seconddistances.end());
     117        ++firstiter, ++seconditer) {
     118      const double gap = *firstiter - *seconditer;
     119      // L1 error
     120      if (errors.first < gap)
     121        errors.first = gap;
     122      // L2 error
     123      errors.second += gap*gap;
     124    }
     125  }
     126
     127  return errors;
     128}
     129
     130SphericalPointDistribution::Polygon_t removeMatchingPoints(
     131    const SphericalPointDistribution::Polygon_t &_points,
     132    const IndexList_t &_matchingindices
     133    )
     134{
     135  SphericalPointDistribution::Polygon_t remainingpoints;
     136  IndexArray_t indices(_matchingindices.begin(), _matchingindices.end());
     137  std::sort(indices.begin(), indices.end());
     138  IndexArray_t::const_iterator valueiter = indices.begin();
     139  SphericalPointDistribution::Polygon_t::const_iterator pointiter =
     140      _points.begin();
     141  for (unsigned int i=0; i< _points.size(); ++i, ++pointiter) {
     142    // skip all those in values
     143    if (*valueiter == i)
     144      ++valueiter;
     145    else
     146      remainingpoints.push_back(*pointiter);
     147  }
     148
     149  return remainingpoints;
     150}
     151
     152/** Rotates a given polygon around x, y, and z axis by the given angles.
     153 *
     154 * Essentially, we concentrate on the three points of the polygon to rotate
     155 * to the correct position. First, we rotate its center via \a angles,
     156 * then we rotate the "triangle" around itself/\a _RotationAxis by
     157 * \a _RotationAngle.
     158 *
     159 * \param _polygon polygon whose points to rotate
     160 * \param _angles vector with rotation angles for x,y,z axis
     161 * \param _RotationAxis
     162 * \param _RotationAngle
     163 */
     164SphericalPointDistribution::Polygon_t rotatePolygon(
     165    const SphericalPointDistribution::Polygon_t &_polygon,
     166    const std::vector<double> &_angles,
     167    const Line &_RotationAxis,
     168    const double _RotationAngle)
     169{
     170  SphericalPointDistribution::Polygon_t rotated_polygon = _polygon;
     171  RealSpaceMatrix rotation;
     172  ASSERT( _angles.size() == 3,
     173      "rotatePolygon() - not exactly "+toString(3)+" angles given.");
     174  rotation.setRotation(_angles[0] * M_PI/180., _angles[1] * M_PI/180., _angles[2] * M_PI/180.);
     175
     176  // apply rotation angles
     177  for (SphericalPointDistribution::Polygon_t::iterator iter = rotated_polygon.begin();
     178      iter != rotated_polygon.end(); ++iter) {
     179    *iter = rotation * (*iter);
     180    _RotationAxis.rotateVector(*iter, _RotationAngle);
     181  }
     182
     183  return rotated_polygon;
     184}
     185
     186struct MatchingControlStructure {
     187  bool foundflag;
     188  double bestL2;
     189  IndexList_t bestmatching;
     190  VectorArray_t oldpoints;
     191  VectorArray_t newpoints;
     192};
     193
     194/** Recursive function to go through all possible matchings.
     195 *
     196 * \param _MCS structure holding global information to the recursion
     197 * \param _matching current matching being build up
     198 * \param _indices contains still available indices
     199 * \param _matchingsize
     200 */
     201void recurseMatchings(
     202    MatchingControlStructure &_MCS,
     203    IndexList_t &_matching,
     204    IndexList_t _indices,
     205    unsigned int _matchingsize)
     206{
     207  //!> threshold for L1 error below which matching is immediately acceptable
     208  const double L1THRESHOLD = 1e-2;
     209  if (!_MCS.foundflag) {
     210    if (_matching.size() < _matchingsize) {
     211      // go through all indices
     212      for (IndexList_t::iterator iter = _indices.begin();
     213          iter != _indices.end();) {
     214        // add index to matching
     215        _matching.push_back(*iter);
     216        // remove index but keep iterator to position (is the next to erase element)
     217        IndexList_t::iterator backupiter = _indices.erase(iter);
     218        // recurse with decreased _matchingsize
     219        recurseMatchings(_MCS, _matching, _indices, _matchingsize-1);
     220        // re-add chosen index and reset index to new position
     221        _indices.insert(backupiter, _matching.back());
     222        iter = backupiter;
     223        // remove index from _matching to make space for the next one
     224        _matching.pop_back();
     225      }
     226      // gone through all indices then exit recursion
     227      _MCS.foundflag = true;
     228    } else {
     229      // calculate errors
     230      std::pair<double, double> errors = calculateErrorOfMatching(
     231          _MCS.oldpoints, _MCS.newpoints, _matching);
     232      if (errors.first < L1THRESHOLD) {
     233        _MCS.bestmatching = _matching;
     234        _MCS.foundflag = true;
     235      }
     236      if (_MCS.bestL2 > errors.second) {
     237        _MCS.bestmatching = _matching;
     238        _MCS.bestL2 = errors.second;
     239      }
     240    }
     241  }
     242}
     243
     244SphericalPointDistribution::Polygon_t
     245SphericalPointDistribution::matchSphericalPointDistributions(
     246    const SphericalPointDistribution::Polygon_t &_polygon,
     247    const SphericalPointDistribution::Polygon_t &_newpolygon
     248    )
     249{
     250  SphericalPointDistribution::Polygon_t remainingpoints;
     251  VectorArray_t remainingold(_polygon.begin(), _polygon.end());
     252  VectorArray_t remainingnew(_newpolygon.begin(), _newpolygon.end());
     253
     254  if (_polygon.size() > 0) {
     255    MatchingControlStructure MCS;
     256    MCS.foundflag = false;
     257    MCS.bestL2 = std::numeric_limits<double>::max();
     258    MCS.oldpoints.insert(MCS.oldpoints.begin(), _polygon.begin(),_polygon.end() );
     259    MCS.newpoints.insert(MCS.newpoints.begin(), _newpolygon.begin(),_newpolygon.end() );
     260
     261    // search for bestmatching combinatorially
     262    {
     263      // translate polygon into vector to enable index addressing
     264      IndexList_t indices(_newpolygon.size());
     265      std::generate(indices.begin(), indices.end(), UniqueNumber);
     266      IndexList_t matching;
     267
     268      // walk through all matchings
     269      const unsigned int matchingsize = _polygon.size();
     270      ASSERT( matchingsize <= indices.size(),
     271          "SphericalPointDistribution::matchSphericalPointDistributions() - not enough new points to choose for matching to old ones.");
     272      recurseMatchings(MCS, matching, indices, matchingsize);
     273    }
     274
     275    // determine rotation angles to align the two point distributions with
     276    // respect to bestmatching
     277    std::vector<double> angles(3);
     278    Vector newCenter;
     279    {
     280      // calculate center of triangle/line/point consisting of first points of matching
     281      Vector oldCenter;
     282      IndexList_t::const_iterator iter = MCS.bestmatching.begin();
     283      unsigned int i = 0;
     284      for (; (i<3) && (i<MCS.bestmatching.size()); ++i, ++iter) {
     285        oldCenter += remainingold[i];
     286        newCenter += remainingnew[*iter];
     287      }
     288      oldCenter *= 1./(double)i;
     289      newCenter *= 1./(double)i;
     290
     291      Vector direction(0.,0.,0.);
     292      for(size_t i=0;i<NDIM;++i) {
     293        // create new rotation axis
     294        direction[i] = 1.;
     295        const Line axis (zeroVec, direction);
     296        // calculate rotation angle for this axis
     297        const double alpha = direction.Angle(oldCenter) - direction.Angle(newCenter);
     298        // perform rotation
     299        axis.rotateVector(newCenter, alpha);
     300        // store angle
     301        angles[i] = alpha;
     302        // reset direction component for next iteration
     303        direction[i] = 0.;
     304      }
     305    }
     306    const Line RotationAxis(zeroVec, newCenter);
     307    const double RotationAngle =
     308        newCenter.Angle(remainingold[0])
     309        - newCenter.Angle(remainingnew[*MCS.bestmatching.begin()]);
     310
     311    // rotate _newpolygon
     312    SphericalPointDistribution::Polygon_t rotated_newpolygon =
     313        rotatePolygon(_newpolygon, angles, RotationAxis, RotationAngle);
     314
     315    // remove all points in matching and return remaining ones
     316    return removeMatchingPoints(rotated_newpolygon, MCS.bestmatching);
     317  } else
     318    return _newpolygon;
     319}
     320
     321
     322
  • src/Fragmentation/Exporters/SphericalPointDistribution.hpp

    rd32f60 r64cafb2  
    5757  }
    5858
    59   /** Initializes the polygon with the given \a _NumberOfPoints.
     59
     60  /** Matches a given spherical distribution with another containing more
     61   * points.
    6062   *
    61    * \param _NumberOfPoints number of points
     63   * This is a helper to determine points where to best insert saturation
     64   * hydrogens.
     65   *
     66   * \param _polygon current occupied positions
     67   * \param _newpolygon ideal distribution to match best with current occupied
     68   *        positions
     69   * \return remaining vacant positions relative to \a _polygon
    6270   */
    63   void initSelf(const int _NumberOfPoints);
     71  static Polygon_t matchSphericalPointDistributions(
     72      const Polygon_t &_polygon,
     73      const Polygon_t &_newpolygon
     74      );
     75
    6476
    6577  //!> default radius of the spherical distribution
     
    6779  //!> precalculated value for root of 3
    6880  const double SQRT_3;
    69   //!> points in this polygon
    70   Polygon_t points;
    7181};
    7282
  • src/Fragmentation/Exporters/unittests/Makefile.am

    rd32f60 r64cafb2  
    55        ../Fragmentation/Exporters/unittests/HydrogenPoolUnitTest.cpp \
    66        ../Fragmentation/Exporters/unittests/SaturatedFragmentUnitTest.cpp \
    7         ../Fragmentation/Exporters/unittests/SaturationDistanceMaximizerUnitTest.cpp
     7        ../Fragmentation/Exporters/unittests/SaturationDistanceMaximizerUnitTest.cpp \
     8        ../Fragmentation/Exporters/unittests/SphericalPointDistributionUnitTest.cpp
    89
    910FRAGMENTATIONEXPORTERSTESTSHEADERS = \
    1011        ../Fragmentation/Exporters/unittests/HydrogenPoolUnitTest.hpp \
    1112        ../Fragmentation/Exporters/unittests/SaturatedFragmentUnitTest.hpp \
    12         ../Fragmentation/Exporters/unittests/SaturationDistanceMaximizerUnitTest.hpp
     13        ../Fragmentation/Exporters/unittests/SaturationDistanceMaximizerUnitTest.hpp \
     14        ../Fragmentation/Exporters/unittests/SphericalPointDistributionUnitTest.hpp
    1315
    1416FRAGMENTATIONEXPORTERSTESTS = \
    1517        HydrogenPoolUnitTest \
    1618        SaturatedFragmentUnitTest \
    17         SaturationDistanceMaximizerUnitTest
     19        SaturationDistanceMaximizerUnitTest \
     20        SphericalPointDistributionUnitTest
    1821
    1922TESTS += $(FRAGMENTATIONEXPORTERSTESTS)
     
    4548
    4649SaturationDistanceMaximizerUnitTest_SOURCES = \
     50        ../Fragmentation/Exporters/unittests/SaturationDistanceMaximizerUnitTest.cpp \
    4751        ../Fragmentation/Exporters/unittests/SaturationDistanceMaximizerUnitTest.hpp \
    4852        ../Fragmentation/Exporters/unittests/stubs/SaturatedBondStub.cpp
     
    5155        $(top_builddir)/LinearAlgebra/src/LinearAlgebra/libLinearAlgebra.la \
    5256        ${FRAGMENTATIONEXPORTERSLIBS}
     57       
     58SphericalPointDistributionUnitTest_SOURCES = \
     59        ../Fragmentation/Exporters/unittests/SphericalPointDistributionUnitTest.cpp \
     60        ../Fragmentation/Exporters/unittests/SphericalPointDistributionUnitTest.hpp
     61SphericalPointDistributionUnitTest_LDADD = \
     62        ../libMolecuilderUI.la  \
     63        $(top_builddir)/LinearAlgebra/src/LinearAlgebra/libLinearAlgebra.la \
     64        ${FRAGMENTATIONEXPORTERSLIBS}
    5365
    5466
Note: See TracChangeset for help on using the changeset viewer.