Ignore:
Timestamp:
Aug 20, 2014, 1:06:16 PM (11 years ago)
Author:
Frederik Heber <heber@…>
Children:
f5fa48
Parents:
c8d2e7
git-author:
Frederik Heber <heber@…> (07/18/14 16:24:53)
git-committer:
Frederik Heber <heber@…> (08/20/14 13:06:16)
Message:

Added getAssociatedPoints().

  • the general problem with getRemainingPoints() for saturating fragments with dangling bonds is that we violate the "Saturation Consistency Principle": Common saturation hydrogens for a specific fragments must remain at the exact same position for all containing fragments.
  • only there do we ascertain that the eigenvalue is (due to the invariance of hydrogen to changes in its chemical neighborhood, valid to a good degree) actually removed by higher order fragments.
  • this function is the first step to calculate a "global" set of saturation positions per atom.
  • added also getIdentityAssociation() in case the association is trivial (i.e. in case of only bonds of degree 1).
File:
1 edited

Legend:

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

    rc8d2e7 rce0ca4  
    10221022}
    10231023
    1024 
     1024SphericalPointDistribution::PolygonWithIndexTuples
     1025SphericalPointDistribution::getAssociatedPoints(
     1026    const WeightedPolygon_t &_polygon,
     1027    const int _N)
     1028{
     1029  SphericalPointDistribution::PolygonWithIndexTuples associatedpoints;
     1030
     1031  // initialze to given number of points
     1032  initSelf(_N);
     1033  LOG(2, "INFO: Matching old polygon " << _polygon
     1034      << " with new polygon " << points);
     1035
     1036  // check whether there are any points to associate
     1037  if (_polygon.empty()) {
     1038    associatedpoints.polygon.insert(
     1039        associatedpoints.polygon.end(),
     1040        points.begin(), points.end());
     1041    return associatedpoints;
     1042  }
     1043
     1044  if (_N > 0) {
     1045    // combine multiple points and create simple IndexList from IndexTupleList
     1046    MatchingControlStructure MCS = findBestMatching(_polygon);
     1047    IndexList_t bestmatching = joinPoints(points, MCS.newpoints, MCS.bestmatching);
     1048    LOG(2, "INFO: Best matching is " << bestmatching);
     1049
     1050    // gather the associated points (not the joined ones)
     1051    associatedpoints.polygon = MCS.newpoints;
     1052    // gather indices
     1053    associatedpoints.indices = MCS.bestmatching;
     1054
     1055    /// now we only need to rotate the associated points to match the given ones
     1056    /// with respect to the joined points in points
     1057
     1058    const size_t NumberIds = std::min(bestmatching.size(), (size_t)3);
     1059    // create old set
     1060    PolygonWithIndices oldSet;
     1061    oldSet.indices.resize(NumberIds, -1);
     1062    std::generate(oldSet.indices.begin(), oldSet.indices.end(), UniqueNumber);
     1063    for (WeightedPolygon_t::const_iterator iter = _polygon.begin();
     1064        iter != _polygon.end(); ++iter)
     1065      oldSet.polygon.push_back(iter->first);
     1066
     1067    // _newpolygon has changed, so now convert to array with matched indices
     1068    PolygonWithIndices newSet;
     1069    SphericalPointDistribution::IndexList_t::const_iterator beginiter = bestmatching.begin();
     1070    SphericalPointDistribution::IndexList_t::const_iterator enditer = bestmatching.begin();
     1071    std::advance(enditer, NumberIds);
     1072    newSet.indices.resize(NumberIds, -1);
     1073    std::copy(beginiter, enditer, newSet.indices.begin());
     1074    std::copy(points.begin(),points.end(), std::back_inserter(newSet.polygon));
     1075
     1076    // determine rotation angles to align the two point distributions with
     1077    // respect to bestmatching:
     1078    // we use the center between the three first matching points
     1079    /// the first rotation brings these two centers to coincide
     1080    PolygonWithIndices rotatednewSet = newSet;
     1081    {
     1082      Rotation_t Rotation = findPlaneAligningRotation(oldSet, newSet);
     1083      LOG(5, "DEBUG: Rotating coordinate system by " << Rotation.second
     1084          << " around axis " << Rotation.first);
     1085      Line Axis(zeroVec, Rotation.first);
     1086
     1087      // apply rotation angle to bring newCenter to oldCenter in joined points
     1088      for (VectorArray_t::iterator iter = rotatednewSet.polygon.begin();
     1089          iter != rotatednewSet.polygon.end(); ++iter) {
     1090        Vector &current = *iter;
     1091        LOG(6, "DEBUG: Original joined point is " << current);
     1092        current =  Axis.rotateVector(current, Rotation.second);
     1093        LOG(6, "DEBUG: Rotated joined point is " << current);
     1094      }
     1095
     1096      // apply rotation angle to the whole set of associated points
     1097      for (VectorArray_t::iterator iter = associatedpoints.polygon.begin();
     1098          iter != associatedpoints.polygon.end(); ++iter) {
     1099        Vector &current = *iter;
     1100        LOG(6, "DEBUG: Original associated point is " << current);
     1101        current =  Axis.rotateVector(current, Rotation.second);
     1102        LOG(6, "DEBUG: Rotated associated point is " << current);
     1103      }
     1104
     1105#ifndef NDEBUG
     1106      // check: rotated "newCenter" should now equal oldCenter
     1107      // we don't check in case of two points as these lie on a great circle
     1108      // and the center cannot stably be recalculated. We may reactivate this
     1109      // when we calculate centers only once
     1110      if (oldSet.indices.size() > 2) {
     1111        Vector oldCenter;
     1112        Vector rotatednewCenter;
     1113        calculateOldAndNewCenters(
     1114            oldCenter, rotatednewCenter,
     1115            oldSet, rotatednewSet);
     1116        oldCenter.Normalize();
     1117        rotatednewCenter.Normalize();
     1118        // check whether centers are anti-parallel (factor -1)
     1119        // then we have the "non-unique poles" situation: points lie on great circle
     1120        // and both poles are valid solution
     1121        if (fabs(oldCenter.ScalarProduct(rotatednewCenter) + 1.)
     1122            < std::numeric_limits<double>::epsilon()*1e4)
     1123          rotatednewCenter *= -1.;
     1124        LOG(4, "CHECK: rotatednewCenter is " << rotatednewCenter
     1125            << ", oldCenter is " << oldCenter);
     1126        const double difference = (rotatednewCenter - oldCenter).NormSquared();
     1127        ASSERT( difference < std::numeric_limits<double>::epsilon()*1e4,
     1128            "matchSphericalPointDistributions() - rotation does not work as expected by "
     1129            +toString(difference)+".");
     1130      }
     1131#endif
     1132    }
     1133    /// the second (orientation) rotation aligns the planes such that the
     1134    /// points themselves coincide
     1135    if (bestmatching.size() > 1) {
     1136      Rotation_t Rotation = findPointAligningRotation(oldSet, rotatednewSet);
     1137
     1138      // construct RotationAxis and two points on its plane, defining the angle
     1139      Rotation.first.Normalize();
     1140      const Line RotationAxis(zeroVec, Rotation.first);
     1141
     1142      LOG(5, "DEBUG: Rotating around self is " << Rotation.second
     1143          << " around axis " << RotationAxis);
     1144
     1145#ifndef NDEBUG
     1146      // check: first bestmatching in rotated_newpolygon and remainingnew
     1147      // should now equal
     1148      {
     1149        const IndexList_t::const_iterator iter = bestmatching.begin();
     1150
     1151        // check whether both old and newPosition are at same distance to oldCenter
     1152        Vector oldCenter = calculateCenter(oldSet);
     1153        const double distance = fabs(
     1154              (oldSet.polygon[0] - oldCenter).NormSquared()
     1155              - (rotatednewSet.polygon[*iter] - oldCenter).NormSquared()
     1156            );
     1157        LOG(4, "CHECK: Squared distance between oldPosition and newPosition "
     1158            << " with respect to oldCenter " << oldCenter << " is " << distance);
     1159//        ASSERT( distance < warn_amplitude,
     1160//            "matchSphericalPointDistributions() - old and newPosition's squared distance to oldCenter differs by "
     1161//            +toString(distance));
     1162
     1163        Vector rotatednew = RotationAxis.rotateVector(
     1164            rotatednewSet.polygon[*iter],
     1165            Rotation.second);
     1166        LOG(4, "CHECK: rotated first new bestmatching is " << rotatednew
     1167            << " while old was " << oldSet.polygon[0]);
     1168        const double difference = (rotatednew - oldSet.polygon[0]).NormSquared();
     1169        ASSERT( difference < distance+1e-8,
     1170            "matchSphericalPointDistributions() - orientation rotation ends up off by "
     1171            +toString(difference)+", more than "
     1172            +toString(distance+1e-8)+".");
     1173      }
     1174#endif
     1175
     1176      // align the set of associated points only here
     1177      for (VectorArray_t::iterator iter = associatedpoints.polygon.begin();
     1178          iter != associatedpoints.polygon.end(); ++iter) {
     1179        Vector &current = *iter;
     1180        LOG(6, "DEBUG: Original associated point is " << current);
     1181        current = RotationAxis.rotateVector(current, Rotation.second);
     1182        LOG(6, "DEBUG: Rotated associated point is " << current);
     1183      }
     1184    }
     1185  }
     1186
     1187  return associatedpoints;
     1188}
     1189
     1190SphericalPointDistribution::PolygonWithIndexTuples
     1191SphericalPointDistribution::getIdentityAssociation(
     1192    const WeightedPolygon_t &_polygon)
     1193{
     1194  unsigned int index = 0;
     1195  SphericalPointDistribution::PolygonWithIndexTuples returnpolygon;
     1196  for (WeightedPolygon_t::const_iterator iter = _polygon.begin();
     1197      iter != _polygon.end(); ++iter, ++index) {
     1198    returnpolygon.polygon.push_back( iter->first );
     1199    ASSERT( iter->second == 1,
     1200        "getIdentityAssociation() - bond with direction "
     1201        +toString(iter->second)
     1202        +" has degree higher than 1, getIdentityAssociation makes no sense.");
     1203    returnpolygon.indices.push_back( IndexList_t(1, index) );
     1204  }
     1205  return returnpolygon;
     1206}
Note: See TracChangeset for help on using the changeset viewer.