| [f54930] | 1 | /*
 | 
|---|
 | 2 |  * Project: MoleCuilder
 | 
|---|
 | 3 |  * Description: creates and alters molecular systems
 | 
|---|
 | 4 |  * Copyright (C)  2014 Frederik Heber. All rights reserved.
 | 
|---|
 | 5 |  *
 | 
|---|
 | 6 |  *
 | 
|---|
 | 7 |  *   This file is part of MoleCuilder.
 | 
|---|
 | 8 |  *
 | 
|---|
 | 9 |  *    MoleCuilder is free software: you can redistribute it and/or modify
 | 
|---|
 | 10 |  *    it under the terms of the GNU General Public License as published by
 | 
|---|
 | 11 |  *    the Free Software Foundation, either version 2 of the License, or
 | 
|---|
 | 12 |  *    (at your option) any later version.
 | 
|---|
 | 13 |  *
 | 
|---|
 | 14 |  *    MoleCuilder is distributed in the hope that it will be useful,
 | 
|---|
 | 15 |  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
 | 16 |  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
 | 17 |  *    GNU General Public License for more details.
 | 
|---|
 | 18 |  *
 | 
|---|
 | 19 |  *    You should have received a copy of the GNU General Public License
 | 
|---|
 | 20 |  *    along with MoleCuilder.  If not, see <http://www.gnu.org/licenses/>.
 | 
|---|
 | 21 |  */
 | 
|---|
 | 22 | 
 | 
|---|
 | 23 | /*
 | 
|---|
 | 24 |  * SphericalPointDistribution.cpp
 | 
|---|
 | 25 |  *
 | 
|---|
 | 26 |  *  Created on: May 30, 2014
 | 
|---|
 | 27 |  *      Author: heber
 | 
|---|
 | 28 |  */
 | 
|---|
 | 29 | 
 | 
|---|
 | 30 | // include config.h
 | 
|---|
 | 31 | #ifdef HAVE_CONFIG_H
 | 
|---|
 | 32 | #include <config.h>
 | 
|---|
 | 33 | #endif
 | 
|---|
 | 34 | 
 | 
|---|
 | 35 | #include "CodePatterns/MemDebug.hpp"
 | 
|---|
 | 36 | 
 | 
|---|
 | 37 | #include "SphericalPointDistribution.hpp"
 | 
|---|
 | 38 | 
 | 
|---|
 | 39 | #include "CodePatterns/Assert.hpp"
 | 
|---|
| [64cafb2] | 40 | #include "CodePatterns/IteratorAdaptors.hpp"
 | 
|---|
| [cdac1d] | 41 | #include "CodePatterns/Log.hpp"
 | 
|---|
| [64cafb2] | 42 | #include "CodePatterns/toString.hpp"
 | 
|---|
| [f54930] | 43 | 
 | 
|---|
 | 44 | #include <algorithm>
 | 
|---|
| [64cafb2] | 45 | #include <cmath>
 | 
|---|
| [022d3b] | 46 | #include <functional>
 | 
|---|
 | 47 | #include <iterator>
 | 
|---|
| [64cafb2] | 48 | #include <limits>
 | 
|---|
 | 49 | #include <list>
 | 
|---|
| [f54930] | 50 | #include <vector>
 | 
|---|
| [64cafb2] | 51 | #include <map>
 | 
|---|
| [f54930] | 52 | 
 | 
|---|
 | 53 | #include "LinearAlgebra/Line.hpp"
 | 
|---|
 | 54 | #include "LinearAlgebra/RealSpaceMatrix.hpp"
 | 
|---|
 | 55 | #include "LinearAlgebra/Vector.hpp"
 | 
|---|
 | 56 | 
 | 
|---|
| [64cafb2] | 57 | typedef std::list<unsigned int> IndexList_t;
 | 
|---|
 | 58 | typedef std::vector<unsigned int> IndexArray_t;
 | 
|---|
 | 59 | typedef std::vector<Vector> VectorArray_t;
 | 
|---|
 | 60 | typedef std::vector<double> DistanceArray_t;
 | 
|---|
 | 61 | 
 | 
|---|
| [cdac1d] | 62 | // static instances
 | 
|---|
 | 63 | const double SphericalPointDistribution::SQRT_3(sqrt(3.0));
 | 
|---|
 | 64 | 
 | 
|---|
| [64cafb2] | 65 | DistanceArray_t calculatePairwiseDistances(
 | 
|---|
| [cdac1d] | 66 |     const std::vector<Vector> &_returnpolygon,
 | 
|---|
| [64cafb2] | 67 |     const IndexList_t &_indices
 | 
|---|
 | 68 |     )
 | 
|---|
 | 69 | {
 | 
|---|
 | 70 |   DistanceArray_t result;
 | 
|---|
 | 71 |   for (IndexList_t::const_iterator firstiter = _indices.begin();
 | 
|---|
 | 72 |       firstiter != _indices.end(); ++firstiter) {
 | 
|---|
 | 73 |     for (IndexList_t::const_iterator seconditer = firstiter;
 | 
|---|
 | 74 |         seconditer != _indices.end(); ++seconditer) {
 | 
|---|
 | 75 |       if (firstiter == seconditer)
 | 
|---|
 | 76 |         continue;
 | 
|---|
| [cdac1d] | 77 |       const double distance = (_returnpolygon[*firstiter] - _returnpolygon[*seconditer]).NormSquared();
 | 
|---|
| [64cafb2] | 78 |       result.push_back(distance);
 | 
|---|
 | 79 |     }
 | 
|---|
 | 80 |   }
 | 
|---|
 | 81 |   return result;
 | 
|---|
 | 82 | }
 | 
|---|
 | 83 | 
 | 
|---|
 | 84 | // class generator: taken from www.cplusplus.com example std::generate
 | 
|---|
 | 85 | struct c_unique {
 | 
|---|
 | 86 |   int current;
 | 
|---|
 | 87 |   c_unique() {current=0;}
 | 
|---|
| [022d3b] | 88 |   int operator()() {return current++;}
 | 
|---|
| [64cafb2] | 89 | } UniqueNumber;
 | 
|---|
 | 90 | 
 | 
|---|
 | 91 | /** Returns squared L2 error of the given \a _Matching.
 | 
|---|
 | 92 |  *
 | 
|---|
 | 93 |  * We compare the pair-wise distances of each associated matching
 | 
|---|
 | 94 |  * and check whether these distances each match between \a _old and
 | 
|---|
 | 95 |  * \a _new.
 | 
|---|
 | 96 |  *
 | 
|---|
| [cdac1d] | 97 |  * \param _old first set of returnpolygon (fewer or equal to \a _new)
 | 
|---|
 | 98 |  * \param _new second set of returnpolygon
 | 
|---|
| [64cafb2] | 99 |  * \param _Matching matching between the two sets
 | 
|---|
 | 100 |  * \return pair with L1 and squared L2 error
 | 
|---|
 | 101 |  */
 | 
|---|
 | 102 | std::pair<double, double> calculateErrorOfMatching(
 | 
|---|
 | 103 |     const std::vector<Vector> &_old,
 | 
|---|
 | 104 |     const std::vector<Vector> &_new,
 | 
|---|
 | 105 |     const IndexList_t &_Matching)
 | 
|---|
 | 106 | {
 | 
|---|
 | 107 |   std::pair<double, double> errors( std::make_pair( 0., 0. ) );
 | 
|---|
 | 108 | 
 | 
|---|
 | 109 |   if (_Matching.size() > 1) {
 | 
|---|
| [0096a40] | 110 |     LOG(3, "INFO: Matching is " << _Matching);
 | 
|---|
| [64cafb2] | 111 | 
 | 
|---|
 | 112 |     // calculate all pair-wise distances
 | 
|---|
 | 113 |     IndexList_t keys(_Matching.size());
 | 
|---|
 | 114 |     std::generate (keys.begin(), keys.end(), UniqueNumber);
 | 
|---|
 | 115 |     const DistanceArray_t firstdistances = calculatePairwiseDistances(_old, keys);
 | 
|---|
 | 116 |     const DistanceArray_t seconddistances = calculatePairwiseDistances(_new, _Matching);
 | 
|---|
 | 117 | 
 | 
|---|
 | 118 |     ASSERT( firstdistances.size() == seconddistances.size(),
 | 
|---|
 | 119 |         "calculateL2ErrorOfMatching() - mismatch in pair-wise distance array sizes.");
 | 
|---|
 | 120 |     DistanceArray_t::const_iterator firstiter = firstdistances.begin();
 | 
|---|
 | 121 |     DistanceArray_t::const_iterator seconditer = seconddistances.begin();
 | 
|---|
 | 122 |     for (;(firstiter != firstdistances.end()) && (seconditer != seconddistances.end());
 | 
|---|
 | 123 |         ++firstiter, ++seconditer) {
 | 
|---|
 | 124 |       const double gap = *firstiter - *seconditer;
 | 
|---|
 | 125 |       // L1 error
 | 
|---|
 | 126 |       if (errors.first < gap)
 | 
|---|
 | 127 |         errors.first = gap;
 | 
|---|
 | 128 |       // L2 error
 | 
|---|
 | 129 |       errors.second += gap*gap;
 | 
|---|
 | 130 |     }
 | 
|---|
| [0096a40] | 131 |   } else
 | 
|---|
| [022d3b] | 132 |     ELOG(3, "calculateErrorOfMatching() - Given matching's size is less than 2.");
 | 
|---|
| [0096a40] | 133 |   LOG(3, "INFO: Resulting errors for matching (L1, L2): "
 | 
|---|
 | 134 |       << errors.first << "," << errors.second << ".");
 | 
|---|
| [64cafb2] | 135 | 
 | 
|---|
 | 136 |   return errors;
 | 
|---|
 | 137 | }
 | 
|---|
 | 138 | 
 | 
|---|
 | 139 | SphericalPointDistribution::Polygon_t removeMatchingPoints(
 | 
|---|
| [cdac1d] | 140 |     const SphericalPointDistribution::Polygon_t &_returnpolygon,
 | 
|---|
| [64cafb2] | 141 |     const IndexList_t &_matchingindices
 | 
|---|
 | 142 |     )
 | 
|---|
 | 143 | {
 | 
|---|
| [cdac1d] | 144 |   SphericalPointDistribution::Polygon_t remainingreturnpolygon;
 | 
|---|
| [64cafb2] | 145 |   IndexArray_t indices(_matchingindices.begin(), _matchingindices.end());
 | 
|---|
 | 146 |   std::sort(indices.begin(), indices.end());
 | 
|---|
| [0096a40] | 147 |   LOG(4, "DEBUG: sorted matching is " << indices);
 | 
|---|
| [64cafb2] | 148 |   IndexArray_t::const_iterator valueiter = indices.begin();
 | 
|---|
 | 149 |   SphericalPointDistribution::Polygon_t::const_iterator pointiter =
 | 
|---|
| [cdac1d] | 150 |       _returnpolygon.begin();
 | 
|---|
 | 151 |   for (unsigned int i=0; i< _returnpolygon.size(); ++i, ++pointiter) {
 | 
|---|
| [64cafb2] | 152 |     // skip all those in values
 | 
|---|
 | 153 |     if (*valueiter == i)
 | 
|---|
 | 154 |       ++valueiter;
 | 
|---|
 | 155 |     else
 | 
|---|
| [cdac1d] | 156 |       remainingreturnpolygon.push_back(*pointiter);
 | 
|---|
| [64cafb2] | 157 |   }
 | 
|---|
| [0096a40] | 158 |   LOG(4, "DEBUG: remaining indices are " << remainingreturnpolygon);
 | 
|---|
| [64cafb2] | 159 | 
 | 
|---|
| [cdac1d] | 160 |   return remainingreturnpolygon;
 | 
|---|
| [64cafb2] | 161 | }
 | 
|---|
 | 162 | 
 | 
|---|
 | 163 | struct MatchingControlStructure {
 | 
|---|
 | 164 |   bool foundflag;
 | 
|---|
 | 165 |   double bestL2;
 | 
|---|
 | 166 |   IndexList_t bestmatching;
 | 
|---|
| [cdac1d] | 167 |   VectorArray_t oldreturnpolygon;
 | 
|---|
 | 168 |   VectorArray_t newreturnpolygon;
 | 
|---|
| [64cafb2] | 169 | };
 | 
|---|
 | 170 | 
 | 
|---|
 | 171 | /** Recursive function to go through all possible matchings.
 | 
|---|
 | 172 |  *
 | 
|---|
 | 173 |  * \param _MCS structure holding global information to the recursion
 | 
|---|
 | 174 |  * \param _matching current matching being build up
 | 
|---|
 | 175 |  * \param _indices contains still available indices
 | 
|---|
 | 176 |  * \param _matchingsize
 | 
|---|
 | 177 |  */
 | 
|---|
 | 178 | void recurseMatchings(
 | 
|---|
 | 179 |     MatchingControlStructure &_MCS,
 | 
|---|
 | 180 |     IndexList_t &_matching,
 | 
|---|
 | 181 |     IndexList_t _indices,
 | 
|---|
 | 182 |     unsigned int _matchingsize)
 | 
|---|
| [f54930] | 183 | {
 | 
|---|
| [0096a40] | 184 |   LOG(4, "DEBUG: Recursing with current matching " << _matching
 | 
|---|
 | 185 |       << ", remaining indices " << _indices
 | 
|---|
| [022d3b] | 186 |       << ", and sought size " << _matching.size()+_matchingsize);
 | 
|---|
| [64cafb2] | 187 |   //!> threshold for L1 error below which matching is immediately acceptable
 | 
|---|
 | 188 |   const double L1THRESHOLD = 1e-2;
 | 
|---|
 | 189 |   if (!_MCS.foundflag) {
 | 
|---|
| [022d3b] | 190 |     LOG(4, "DEBUG: Current matching has size " << _matching.size() << ", places left " << _matchingsize);
 | 
|---|
 | 191 |     if (_matchingsize > 0) {
 | 
|---|
| [64cafb2] | 192 |       // go through all indices
 | 
|---|
 | 193 |       for (IndexList_t::iterator iter = _indices.begin();
 | 
|---|
| [022d3b] | 194 |           (iter != _indices.end()) && (!_MCS.foundflag);) {
 | 
|---|
| [64cafb2] | 195 |         // add index to matching
 | 
|---|
 | 196 |         _matching.push_back(*iter);
 | 
|---|
| [022d3b] | 197 |         LOG(5, "DEBUG: Adding " << *iter << " to matching.");
 | 
|---|
| [64cafb2] | 198 |         // remove index but keep iterator to position (is the next to erase element)
 | 
|---|
 | 199 |         IndexList_t::iterator backupiter = _indices.erase(iter);
 | 
|---|
 | 200 |         // recurse with decreased _matchingsize
 | 
|---|
 | 201 |         recurseMatchings(_MCS, _matching, _indices, _matchingsize-1);
 | 
|---|
 | 202 |         // re-add chosen index and reset index to new position
 | 
|---|
 | 203 |         _indices.insert(backupiter, _matching.back());
 | 
|---|
 | 204 |         iter = backupiter;
 | 
|---|
 | 205 |         // remove index from _matching to make space for the next one
 | 
|---|
 | 206 |         _matching.pop_back();
 | 
|---|
 | 207 |       }
 | 
|---|
 | 208 |       // gone through all indices then exit recursion
 | 
|---|
| [022d3b] | 209 |       if (_matching.empty())
 | 
|---|
 | 210 |         _MCS.foundflag = true;
 | 
|---|
| [64cafb2] | 211 |     } else {
 | 
|---|
| [0096a40] | 212 |       LOG(3, "INFO: Found matching " << _matching);
 | 
|---|
| [64cafb2] | 213 |       // calculate errors
 | 
|---|
 | 214 |       std::pair<double, double> errors = calculateErrorOfMatching(
 | 
|---|
| [cdac1d] | 215 |           _MCS.oldreturnpolygon, _MCS.newreturnpolygon, _matching);
 | 
|---|
| [64cafb2] | 216 |       if (errors.first < L1THRESHOLD) {
 | 
|---|
 | 217 |         _MCS.bestmatching = _matching;
 | 
|---|
 | 218 |         _MCS.foundflag = true;
 | 
|---|
| [022d3b] | 219 |       } else if (_MCS.bestL2 > errors.second) {
 | 
|---|
| [64cafb2] | 220 |         _MCS.bestmatching = _matching;
 | 
|---|
 | 221 |         _MCS.bestL2 = errors.second;
 | 
|---|
 | 222 |       }
 | 
|---|
 | 223 |     }
 | 
|---|
| [f54930] | 224 |   }
 | 
|---|
 | 225 | }
 | 
|---|
 | 226 | 
 | 
|---|
| [022d3b] | 227 | /** Convert cartesian to polar coordinates.
 | 
|---|
 | 228 |  *
 | 
|---|
 | 229 |  * \param _cartesian vector in cartesian coordinates
 | 
|---|
 | 230 |  * \return vector containing \f$ (r,\theta, \varphi \f$ tuple for polar coordinates
 | 
|---|
 | 231 |  */
 | 
|---|
 | 232 | std::vector<double> getPolarCoordinates(const Vector &_cartesian)
 | 
|---|
 | 233 | {
 | 
|---|
 | 234 |   std::vector<double> polar(3,0.);
 | 
|---|
 | 235 |   const double xsqr = _cartesian[0] * _cartesian[0];
 | 
|---|
 | 236 |   const double ysqr = _cartesian[1] * _cartesian[1];
 | 
|---|
 | 237 |   polar[0] = sqrt(xsqr + ysqr + _cartesian[2]*_cartesian[2]);
 | 
|---|
 | 238 |   if (fabs(_cartesian[2]) < std::numeric_limits<double>::epsilon()*1e4) {
 | 
|---|
 | 239 |     if (fabs(xsqr + ysqr) < std::numeric_limits<double>::epsilon()*1e4) {
 | 
|---|
 | 240 |       polar[1] = 0.;
 | 
|---|
 | 241 |     } else {
 | 
|---|
 | 242 |       // xsqr + ysqr is always non-negative
 | 
|---|
 | 243 |       polar[1] = M_PI/2.;
 | 
|---|
 | 244 |     }
 | 
|---|
 | 245 |   } else {
 | 
|---|
 | 246 |     polar[1] = atan( sqrt(xsqr + ysqr)/_cartesian[2]);
 | 
|---|
 | 247 |     if (_cartesian[2] <= -std::numeric_limits<double>::epsilon()*1e4)
 | 
|---|
 | 248 |       polar[1] += M_PI;
 | 
|---|
 | 249 |   }
 | 
|---|
 | 250 | 
 | 
|---|
 | 251 |   if (fabs(_cartesian[0]) < std::numeric_limits<double>::epsilon()*1e4) {
 | 
|---|
 | 252 |     if (fabs(_cartesian[1]) < std::numeric_limits<double>::epsilon()*1e4) {
 | 
|---|
 | 253 |       polar[2] = 0.;
 | 
|---|
 | 254 |     } else if (_cartesian[1] > std::numeric_limits<double>::epsilon()*1e4) {
 | 
|---|
 | 255 |       polar[2] = M_PI/2.;
 | 
|---|
 | 256 |     } else {
 | 
|---|
 | 257 |       polar[2] = -M_PI/2.;
 | 
|---|
 | 258 |     }
 | 
|---|
 | 259 |   } else {
 | 
|---|
 | 260 |     polar[2] = atan ( _cartesian[1]/_cartesian[0] );
 | 
|---|
 | 261 |     if (_cartesian[0] <= -std::numeric_limits<double>::epsilon()*1e4)
 | 
|---|
 | 262 |       polar[2] += M_PI;
 | 
|---|
 | 263 |   }
 | 
|---|
 | 264 |   return polar;
 | 
|---|
 | 265 | }
 | 
|---|
 | 266 | 
 | 
|---|
 | 267 | /** Calculate cartesian coordinates from given polar ones.
 | 
|---|
 | 268 |  *
 | 
|---|
 | 269 |  * \param _polar vector with polar coordinates
 | 
|---|
 | 270 |  * \return cartesian coordinates
 | 
|---|
 | 271 |  */
 | 
|---|
 | 272 | Vector getCartesianCoordinates(const std::vector<double> &_polar)
 | 
|---|
 | 273 | {
 | 
|---|
 | 274 |   Vector cartesian;
 | 
|---|
 | 275 |   ASSERT( _polar.size() == 3,
 | 
|---|
 | 276 |       "convertToCartesianCoordinates() - tuples has insufficient components.");
 | 
|---|
 | 277 |   cartesian[0] = _polar[0] * sin(_polar[1]) * cos(_polar[2]);
 | 
|---|
 | 278 |   cartesian[1] = _polar[0] * sin(_polar[1]) * sin(_polar[2]);
 | 
|---|
 | 279 |   cartesian[2] = _polar[0] * cos(_polar[1]);
 | 
|---|
 | 280 |   return cartesian;
 | 
|---|
 | 281 | }
 | 
|---|
 | 282 | 
 | 
|---|
 | 283 | /** Rotates a given polygon around x, y, and z axis by the given angles.
 | 
|---|
 | 284 |  *
 | 
|---|
 | 285 |  * \param _polygon polygon whose points to rotate
 | 
|---|
 | 286 |  * \param _angles vector with rotation angles for x,y,z axis
 | 
|---|
 | 287 |  */
 | 
|---|
 | 288 | SphericalPointDistribution::Polygon_t rotatePolygon(
 | 
|---|
 | 289 |     const SphericalPointDistribution::Polygon_t &_polygon,
 | 
|---|
 | 290 |     const std::vector<double> &_angles)
 | 
|---|
 | 291 | {
 | 
|---|
 | 292 |   SphericalPointDistribution::Polygon_t rotated_polygon = _polygon;
 | 
|---|
 | 293 |   RealSpaceMatrix rotation;
 | 
|---|
 | 294 |   ASSERT( _angles.size() == 3,
 | 
|---|
 | 295 |       "rotatePolygon() - not exactly "+toString(3)+" components given.");
 | 
|---|
 | 296 | 
 | 
|---|
 | 297 |   // apply rotation angles
 | 
|---|
 | 298 |   for (SphericalPointDistribution::Polygon_t::iterator iter = rotated_polygon.begin();
 | 
|---|
 | 299 |       iter != rotated_polygon.end(); ++iter) {
 | 
|---|
 | 300 |     // transform to polar
 | 
|---|
 | 301 |     std::vector<double> polar = getPolarCoordinates(*iter);
 | 
|---|
 | 302 |     LOG(5, "DEBUG: Converting " << *iter << " to " << polar);
 | 
|---|
 | 303 |     // sum up difference
 | 
|---|
 | 304 |     std::transform(
 | 
|---|
 | 305 |         _angles.begin(), _angles.end(),
 | 
|---|
 | 306 |         polar.begin(),
 | 
|---|
 | 307 |         polar.begin(),
 | 
|---|
 | 308 |         std::plus<double>());
 | 
|---|
 | 309 |     // convert back
 | 
|---|
 | 310 |     *iter = getCartesianCoordinates(polar);
 | 
|---|
 | 311 |     LOG(5, "DEBUG: Converting modified " << polar << " to " << *iter);
 | 
|---|
 | 312 |   }
 | 
|---|
 | 313 | 
 | 
|---|
 | 314 |   return rotated_polygon;
 | 
|---|
 | 315 | }
 | 
|---|
 | 316 | 
 | 
|---|
 | 317 | 
 | 
|---|
| [64cafb2] | 318 | SphericalPointDistribution::Polygon_t
 | 
|---|
 | 319 | SphericalPointDistribution::matchSphericalPointDistributions(
 | 
|---|
 | 320 |     const SphericalPointDistribution::Polygon_t &_polygon,
 | 
|---|
 | 321 |     const SphericalPointDistribution::Polygon_t &_newpolygon
 | 
|---|
 | 322 |     )
 | 
|---|
 | 323 | {
 | 
|---|
| [cdac1d] | 324 |   SphericalPointDistribution::Polygon_t remainingreturnpolygon;
 | 
|---|
| [64cafb2] | 325 |   VectorArray_t remainingold(_polygon.begin(), _polygon.end());
 | 
|---|
 | 326 |   VectorArray_t remainingnew(_newpolygon.begin(), _newpolygon.end());
 | 
|---|
| [022d3b] | 327 |   LOG(2, "INFO: Matching old polygon " << _polygon
 | 
|---|
| [0096a40] | 328 |       << " with new polygon " << _newpolygon);
 | 
|---|
| [64cafb2] | 329 | 
 | 
|---|
 | 330 |   if (_polygon.size() > 0) {
 | 
|---|
 | 331 |     MatchingControlStructure MCS;
 | 
|---|
 | 332 |     MCS.foundflag = false;
 | 
|---|
 | 333 |     MCS.bestL2 = std::numeric_limits<double>::max();
 | 
|---|
| [cdac1d] | 334 |     MCS.oldreturnpolygon.insert(MCS.oldreturnpolygon.begin(), _polygon.begin(),_polygon.end() );
 | 
|---|
 | 335 |     MCS.newreturnpolygon.insert(MCS.newreturnpolygon.begin(), _newpolygon.begin(),_newpolygon.end() );
 | 
|---|
| [64cafb2] | 336 | 
 | 
|---|
 | 337 |     // search for bestmatching combinatorially
 | 
|---|
 | 338 |     {
 | 
|---|
 | 339 |       // translate polygon into vector to enable index addressing
 | 
|---|
 | 340 |       IndexList_t indices(_newpolygon.size());
 | 
|---|
 | 341 |       std::generate(indices.begin(), indices.end(), UniqueNumber);
 | 
|---|
 | 342 |       IndexList_t matching;
 | 
|---|
 | 343 | 
 | 
|---|
 | 344 |       // walk through all matchings
 | 
|---|
 | 345 |       const unsigned int matchingsize = _polygon.size();
 | 
|---|
 | 346 |       ASSERT( matchingsize <= indices.size(),
 | 
|---|
| [cdac1d] | 347 |           "SphericalPointDistribution::matchSphericalPointDistributions() - not enough new returnpolygon to choose for matching to old ones.");
 | 
|---|
| [64cafb2] | 348 |       recurseMatchings(MCS, matching, indices, matchingsize);
 | 
|---|
 | 349 |     }
 | 
|---|
| [022d3b] | 350 |     LOG(2, "INFO: Best matching is " << MCS.bestmatching);
 | 
|---|
| [64cafb2] | 351 | 
 | 
|---|
 | 352 |     // determine rotation angles to align the two point distributions with
 | 
|---|
 | 353 |     // respect to bestmatching
 | 
|---|
| [022d3b] | 354 |     std::vector<double> angles(NDIM);
 | 
|---|
| [64cafb2] | 355 |     Vector newCenter;
 | 
|---|
| [022d3b] | 356 |     Vector oldCenter;
 | 
|---|
| [64cafb2] | 357 |     {
 | 
|---|
| [022d3b] | 358 |       // calculate center of triangle/line/point consisting of first points of matching
 | 
|---|
| [64cafb2] | 359 |       IndexList_t::const_iterator iter = MCS.bestmatching.begin();
 | 
|---|
 | 360 |       unsigned int i = 0;
 | 
|---|
 | 361 |       for (; (i<3) && (i<MCS.bestmatching.size()); ++i, ++iter) {
 | 
|---|
 | 362 |         oldCenter += remainingold[i];
 | 
|---|
 | 363 |         newCenter += remainingnew[*iter];
 | 
|---|
 | 364 |       }
 | 
|---|
 | 365 |       oldCenter *= 1./(double)i;
 | 
|---|
 | 366 |       newCenter *= 1./(double)i;
 | 
|---|
| [022d3b] | 367 |       LOG(4, "DEBUG: oldCenter is " << oldCenter << ", newCenter is " << newCenter);
 | 
|---|
 | 368 | 
 | 
|---|
 | 369 |       // transform to polar coordinates and note difference in angular parts
 | 
|---|
 | 370 |       std::vector<double> oldpolar = getPolarCoordinates(oldCenter);
 | 
|---|
 | 371 |       std::vector<double> newpolar = getPolarCoordinates(newCenter);
 | 
|---|
 | 372 |       std::vector<double> differencepolar;
 | 
|---|
 | 373 |       std::transform(
 | 
|---|
 | 374 |           oldpolar.begin(), oldpolar.end(),
 | 
|---|
 | 375 |           newpolar.begin(),
 | 
|---|
 | 376 |           std::back_inserter(differencepolar),
 | 
|---|
 | 377 |           std::minus<double>());
 | 
|---|
 | 378 |       LOG(3, "INFO: (r,theta,phi) angles are" << differencepolar);
 | 
|---|
| [64cafb2] | 379 |     }
 | 
|---|
| [022d3b] | 380 |     // rotate _newpolygon
 | 
|---|
 | 381 |     SphericalPointDistribution::Polygon_t rotated_newpolygon =
 | 
|---|
 | 382 |         rotatePolygon(_newpolygon, angles);
 | 
|---|
 | 383 |     LOG(5, "DEBUG: Rotated new polygon is " << rotated_newpolygon);
 | 
|---|
 | 384 | 
 | 
|---|
 | 385 |     const Line RotationAxis(zeroVec, oldCenter);
 | 
|---|
| [64cafb2] | 386 |     const double RotationAngle =
 | 
|---|
| [022d3b] | 387 |         oldCenter.Angle(remainingold[0])
 | 
|---|
 | 388 |         - oldCenter.Angle(remainingnew[*MCS.bestmatching.begin()]);
 | 
|---|
 | 389 |     LOG(5, "DEBUG: Rotate around self is " << RotationAngle
 | 
|---|
| [19bfb5] | 390 |         << " around axis " << RotationAxis);
 | 
|---|
| [64cafb2] | 391 | 
 | 
|---|
| [022d3b] | 392 |     for (SphericalPointDistribution::Polygon_t::iterator iter = rotated_newpolygon.begin();
 | 
|---|
 | 393 |         iter != rotated_newpolygon.end(); ++iter) {
 | 
|---|
 | 394 |       RotationAxis.rotateVector(*iter, RotationAngle);
 | 
|---|
 | 395 |     }
 | 
|---|
| [64cafb2] | 396 | 
 | 
|---|
| [022d3b] | 397 |     // remove all points in matching and return remaining ones
 | 
|---|
 | 398 |     SphericalPointDistribution::Polygon_t remainingpoints =
 | 
|---|
 | 399 |         removeMatchingPoints(rotated_newpolygon, MCS.bestmatching);
 | 
|---|
 | 400 |     LOG(2, "INFO: Remaining points are " << remainingpoints);
 | 
|---|
 | 401 |     return remainingpoints;
 | 
|---|
| [64cafb2] | 402 |   } else
 | 
|---|
 | 403 |     return _newpolygon;
 | 
|---|
 | 404 | }
 | 
|---|