| [8eb17a] | 1 | #include "molecules.hpp" | 
|---|
|  | 2 | #include "boundary.hpp" | 
|---|
|  | 3 |  | 
|---|
|  | 4 | // ======================================== Points on Boundary ================================= | 
|---|
|  | 5 |  | 
|---|
|  | 6 | BoundaryPointSet::BoundaryPointSet() | 
|---|
|  | 7 | { | 
|---|
|  | 8 | LinesCount = 0; | 
|---|
|  | 9 | Nr = -1; | 
|---|
|  | 10 | }; | 
|---|
|  | 11 |  | 
|---|
|  | 12 | BoundaryPointSet::BoundaryPointSet(atom *Walker) | 
|---|
|  | 13 | { | 
|---|
|  | 14 | node = Walker; | 
|---|
|  | 15 | LinesCount = 0; | 
|---|
|  | 16 | Nr = Walker->nr; | 
|---|
|  | 17 | }; | 
|---|
|  | 18 |  | 
|---|
|  | 19 | BoundaryPointSet::~BoundaryPointSet() | 
|---|
|  | 20 | { | 
|---|
|  | 21 | cout << Verbose(5) << "Erasing point nr. " << Nr << "." << endl; | 
|---|
|  | 22 | node = NULL; | 
|---|
|  | 23 | }; | 
|---|
|  | 24 |  | 
|---|
|  | 25 | void BoundaryPointSet::AddLine(class BoundaryLineSet *line) | 
|---|
|  | 26 | { | 
|---|
|  | 27 | cout << Verbose(6) << "Adding line " << *line << " to " << *this << "." << endl; | 
|---|
|  | 28 | if (line->endpoints[0] == this) { | 
|---|
|  | 29 | lines.insert ( LinePair( line->endpoints[1]->Nr, line) ); | 
|---|
|  | 30 | } else { | 
|---|
|  | 31 | lines.insert ( LinePair( line->endpoints[0]->Nr, line) ); | 
|---|
|  | 32 | } | 
|---|
|  | 33 | LinesCount++; | 
|---|
|  | 34 | }; | 
|---|
|  | 35 |  | 
|---|
|  | 36 | ostream & operator << (ostream &ost, BoundaryPointSet &a) | 
|---|
|  | 37 | { | 
|---|
|  | 38 | ost << "[" << a.Nr << "|" << a.node->Name << "]"; | 
|---|
|  | 39 | return ost; | 
|---|
|  | 40 | }; | 
|---|
|  | 41 |  | 
|---|
|  | 42 | // ======================================== Lines on Boundary ================================= | 
|---|
|  | 43 |  | 
|---|
|  | 44 | BoundaryLineSet::BoundaryLineSet() | 
|---|
|  | 45 | { | 
|---|
|  | 46 | for (int i=0;i<2;i++) | 
|---|
|  | 47 | endpoints[i] = NULL; | 
|---|
|  | 48 | TrianglesCount = 0; | 
|---|
|  | 49 | Nr = -1; | 
|---|
|  | 50 | }; | 
|---|
|  | 51 |  | 
|---|
|  | 52 | BoundaryLineSet::BoundaryLineSet(class BoundaryPointSet *Point[2], int number) | 
|---|
|  | 53 | { | 
|---|
|  | 54 | // set number | 
|---|
|  | 55 | Nr = number; | 
|---|
|  | 56 | // set endpoints in ascending order | 
|---|
|  | 57 | SetEndpointsOrdered(endpoints, Point[0], Point[1]); | 
|---|
|  | 58 | // add this line to the hash maps of both endpoints | 
|---|
|  | 59 | Point[0]->AddLine(this); | 
|---|
|  | 60 | Point[1]->AddLine(this); | 
|---|
|  | 61 | // clear triangles list | 
|---|
|  | 62 | TrianglesCount = 0; | 
|---|
|  | 63 | cout << Verbose(5) << "New Line with endpoints " << *this << "." << endl; | 
|---|
|  | 64 | }; | 
|---|
|  | 65 |  | 
|---|
|  | 66 | BoundaryLineSet::~BoundaryLineSet() | 
|---|
|  | 67 | { | 
|---|
|  | 68 | for (int i=0;i<2;i++) { | 
|---|
|  | 69 | cout << Verbose(5) << "Erasing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl; | 
|---|
|  | 70 | endpoints[i]->lines.erase(Nr); | 
|---|
|  | 71 | LineMap::iterator tester = endpoints[i]->lines.begin(); | 
|---|
|  | 72 | tester++; | 
|---|
|  | 73 | if (tester == endpoints[i]->lines.end()) { | 
|---|
|  | 74 | cout << Verbose(5) << *endpoints[i] << " has no more lines it's attached to, erasing." << endl; | 
|---|
|  | 75 | delete(endpoints[i]); | 
|---|
|  | 76 | } else | 
|---|
|  | 77 | cout << Verbose(5) << *endpoints[i] << " has still lines it's attached to." << endl; | 
|---|
|  | 78 | } | 
|---|
|  | 79 | }; | 
|---|
|  | 80 |  | 
|---|
|  | 81 | void BoundaryLineSet::AddTriangle(class BoundaryTriangleSet *triangle) | 
|---|
|  | 82 | { | 
|---|
|  | 83 | cout << Verbose(6) << "Add " << triangle->Nr << " to line " << *this << "." << endl; | 
|---|
|  | 84 | triangles.insert ( TrianglePair( TrianglesCount, triangle) ); | 
|---|
|  | 85 | TrianglesCount++; | 
|---|
|  | 86 | }; | 
|---|
|  | 87 |  | 
|---|
|  | 88 | ostream & operator << (ostream &ost, BoundaryLineSet &a) | 
|---|
|  | 89 | { | 
|---|
|  | 90 | ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << "," << a.endpoints[1]->node->Name << "]"; | 
|---|
|  | 91 | return ost; | 
|---|
|  | 92 | }; | 
|---|
|  | 93 |  | 
|---|
|  | 94 | // ======================================== Triangles on Boundary ================================= | 
|---|
|  | 95 |  | 
|---|
|  | 96 |  | 
|---|
|  | 97 | BoundaryTriangleSet::BoundaryTriangleSet() | 
|---|
|  | 98 | { | 
|---|
|  | 99 | for (int i=0;i<3;i++) { | 
|---|
|  | 100 | endpoints[i] = NULL; | 
|---|
|  | 101 | lines[i] = NULL; | 
|---|
|  | 102 | } | 
|---|
|  | 103 | Nr = -1; | 
|---|
|  | 104 | }; | 
|---|
|  | 105 |  | 
|---|
|  | 106 | BoundaryTriangleSet::BoundaryTriangleSet(class BoundaryLineSet *line[3], int number) | 
|---|
|  | 107 | { | 
|---|
|  | 108 | // set number | 
|---|
|  | 109 | Nr = number; | 
|---|
|  | 110 | // set lines | 
|---|
|  | 111 | cout << Verbose(5) << "New triangle " << Nr << ":" << endl; | 
|---|
|  | 112 | for (int i=0;i<3;i++) { | 
|---|
|  | 113 | lines[i] = line[i]; | 
|---|
|  | 114 | lines[i]->AddTriangle(this); | 
|---|
|  | 115 | } | 
|---|
|  | 116 | // get ascending order of endpoints | 
|---|
|  | 117 | map <int, class BoundaryPointSet * > OrderMap; | 
|---|
|  | 118 | for(int i=0;i<3;i++)  // for all three lines | 
|---|
|  | 119 | for (int j=0;j<2;j++) { // for both endpoints | 
|---|
|  | 120 | OrderMap.insert ( pair <int, class BoundaryPointSet * >( line[i]->endpoints[j]->Nr, line[i]->endpoints[j]) ); | 
|---|
|  | 121 | // and we don't care whether insertion fails | 
|---|
|  | 122 | } | 
|---|
|  | 123 | // set endpoints | 
|---|
|  | 124 | int Counter = 0; | 
|---|
|  | 125 | cout << Verbose(6) << " with end points "; | 
|---|
|  | 126 | for (map <int, class BoundaryPointSet * >::iterator runner = OrderMap.begin(); runner != OrderMap.end(); runner++) { | 
|---|
|  | 127 | endpoints[Counter] = runner->second; | 
|---|
|  | 128 | cout << " " << *endpoints[Counter]; | 
|---|
|  | 129 | Counter++; | 
|---|
|  | 130 | } | 
|---|
|  | 131 | if (Counter < 3) { | 
|---|
|  | 132 | cerr << "ERROR! We have a triangle with only two distinct endpoints!" << endl; | 
|---|
|  | 133 | //exit(1); | 
|---|
|  | 134 | } | 
|---|
|  | 135 | cout << "." << endl; | 
|---|
|  | 136 | }; | 
|---|
|  | 137 |  | 
|---|
|  | 138 | BoundaryTriangleSet::~BoundaryTriangleSet() | 
|---|
|  | 139 | { | 
|---|
|  | 140 | for (int i=0;i<3;i++) { | 
|---|
|  | 141 | cout << Verbose(5) << "Erasing triangle Nr." << Nr << endl; | 
|---|
|  | 142 | lines[i]->triangles.erase(Nr); | 
|---|
|  | 143 | TriangleMap::iterator tester = lines[i]->triangles.begin(); | 
|---|
|  | 144 | tester++; | 
|---|
|  | 145 | if (tester == lines[i]->triangles.end()) { | 
|---|
|  | 146 | cout << Verbose(5) << *lines[i] << " is no more attached to any triangle, erasing." << endl; | 
|---|
|  | 147 | delete(lines[i]); | 
|---|
|  | 148 | } else | 
|---|
|  | 149 | cout << Verbose(5) << *lines[i] << " is still attached to a triangle." << endl; | 
|---|
|  | 150 | } | 
|---|
|  | 151 | }; | 
|---|
|  | 152 |  | 
|---|
|  | 153 | void BoundaryTriangleSet::GetNormalVector(vector &NormalVector) | 
|---|
|  | 154 | { | 
|---|
|  | 155 | // get normal vector | 
|---|
|  | 156 | NormalVector.MakeNormalVector(&endpoints[0]->node->x, &endpoints[1]->node->x, &endpoints[2]->node->x); | 
|---|
|  | 157 |  | 
|---|
|  | 158 | // make it always point inward (any offset vector onto plane projected onto normal vector suffices) | 
|---|
|  | 159 | if (endpoints[0]->node->x.Projection(&NormalVector) > 0) | 
|---|
|  | 160 | NormalVector.Scale(-1.); | 
|---|
|  | 161 | }; | 
|---|
|  | 162 |  | 
|---|
|  | 163 | ostream & operator << (ostream &ost, BoundaryTriangleSet &a) | 
|---|
|  | 164 | { | 
|---|
|  | 165 | ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << "," << a.endpoints[1]->node->Name << "," << a.endpoints[2]->node->Name << "]"; | 
|---|
|  | 166 | return ost; | 
|---|
|  | 167 | }; | 
|---|
|  | 168 |  | 
|---|
|  | 169 | // ========================================== F U N C T I O N S ================================= | 
|---|
|  | 170 |  | 
|---|
|  | 171 | class BoundaryPointSet * GetCommonEndpoint(class BoundaryLineSet * line1, class BoundaryLineSet * line2) | 
|---|
|  | 172 | { | 
|---|
|  | 173 | class BoundaryLineSet * lines[2] = {line1, line2}; | 
|---|
|  | 174 | class BoundaryPointSet *node = NULL; | 
|---|
|  | 175 | map <int, class BoundaryPointSet * > OrderMap; | 
|---|
|  | 176 | pair < map <int, class BoundaryPointSet * >::iterator, bool > OrderTest; | 
|---|
|  | 177 | for(int i=0;i<2;i++)  // for both lines | 
|---|
|  | 178 | for (int j=0;j<2;j++) { // for both endpoints | 
|---|
|  | 179 | OrderTest = OrderMap.insert ( pair <int, class BoundaryPointSet * >( lines[i]->endpoints[j]->Nr, lines[i]->endpoints[j]) ); | 
|---|
|  | 180 | if (!OrderTest.second) { // if insertion fails, we have common endpoint | 
|---|
|  | 181 | node = OrderTest.first->second; | 
|---|
|  | 182 | cout << Verbose(5) << "Common endpoint of lines " << *line1 << " and " << *line2 << " is: " << *node << "." << endl; | 
|---|
|  | 183 | j=2; | 
|---|
|  | 184 | i=2; | 
|---|
|  | 185 | break; | 
|---|
|  | 186 | } | 
|---|
|  | 187 | } | 
|---|
|  | 188 | return node; | 
|---|
|  | 189 | }; | 
|---|
|  | 190 |  | 
|---|
|  | 191 | /** Determines the boundary points of a cluster. | 
|---|
|  | 192 | * Does a projection per axis onto the orthogonal plane, transforms into spherical coordinates, sorts them by the angle | 
|---|
|  | 193 | * and looks at triples: if the middle has less a distance than the allowed maximum height of the triangle formed by the plane's | 
|---|
|  | 194 | * center and first and last point in the triple, it is thrown out. | 
|---|
|  | 195 | * \param *out output stream for debugging | 
|---|
|  | 196 | * \param *mol molecule structure representing the cluster | 
|---|
|  | 197 | */ | 
|---|
|  | 198 | Boundaries * GetBoundaryPoints(ofstream *out, molecule *mol) | 
|---|
|  | 199 | { | 
|---|
|  | 200 | atom *Walker = NULL; | 
|---|
|  | 201 | PointMap PointsOnBoundary; | 
|---|
|  | 202 | LineMap LinesOnBoundary; | 
|---|
|  | 203 | TriangleMap TrianglesOnBoundary; | 
|---|
|  | 204 |  | 
|---|
|  | 205 | *out << Verbose(1) << "Finding all boundary points." << endl; | 
|---|
|  | 206 | Boundaries *BoundaryPoints = new Boundaries [NDIM];  // first is alpha, second is (r, nr) | 
|---|
|  | 207 | BoundariesTestPair BoundaryTestPair; | 
|---|
|  | 208 | vector AxisVector, AngleReferenceVector, AngleReferenceNormalVector; | 
|---|
|  | 209 | double radius, angle; | 
|---|
|  | 210 | // 3a. Go through every axis | 
|---|
|  | 211 | for (int axis=0; axis<NDIM; axis++)  { | 
|---|
|  | 212 | AxisVector.Zero(); | 
|---|
|  | 213 | AngleReferenceVector.Zero(); | 
|---|
|  | 214 | AngleReferenceNormalVector.Zero(); | 
|---|
|  | 215 | AxisVector.x[axis] = 1.; | 
|---|
|  | 216 | AngleReferenceVector.x[(axis+1)%NDIM] = 1.; | 
|---|
|  | 217 | AngleReferenceNormalVector.x[(axis+2)%NDIM] = 1.; | 
|---|
|  | 218 | //    *out << Verbose(1) << "Axisvector is "; | 
|---|
|  | 219 | //    AxisVector.Output(out); | 
|---|
|  | 220 | //    *out << " and AngleReferenceVector is "; | 
|---|
|  | 221 | //    AngleReferenceVector.Output(out); | 
|---|
|  | 222 | //    *out << "." << endl; | 
|---|
|  | 223 | //    *out << " and AngleReferenceNormalVector is "; | 
|---|
|  | 224 | //    AngleReferenceNormalVector.Output(out); | 
|---|
|  | 225 | //    *out << "." << endl; | 
|---|
|  | 226 | // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours | 
|---|
|  | 227 | Walker = mol->start; | 
|---|
|  | 228 | while (Walker->next != mol->end) { | 
|---|
|  | 229 | Walker = Walker->next; | 
|---|
|  | 230 | vector ProjectedVector; | 
|---|
|  | 231 | ProjectedVector.CopyVector(&Walker->x); | 
|---|
|  | 232 | ProjectedVector.ProjectOntoPlane(&AxisVector); | 
|---|
|  | 233 | // correct for negative side | 
|---|
|  | 234 | //if (Projection(y) < 0) | 
|---|
|  | 235 | //angle = 2.*M_PI - angle; | 
|---|
|  | 236 | radius = ProjectedVector.Norm(); | 
|---|
|  | 237 | if (fabs(radius) > MYEPSILON) | 
|---|
|  | 238 | angle = ProjectedVector.Angle(&AngleReferenceVector); | 
|---|
|  | 239 | else | 
|---|
|  | 240 | angle = 0.;  // otherwise it's a vector in Axis Direction and unimportant for boundary issues | 
|---|
|  | 241 |  | 
|---|
|  | 242 | //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl; | 
|---|
|  | 243 | if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0) { | 
|---|
|  | 244 | angle = 2.*M_PI - angle; | 
|---|
|  | 245 | } | 
|---|
|  | 246 | //*out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): "; | 
|---|
|  | 247 | //ProjectedVector.Output(out); | 
|---|
|  | 248 | //*out << endl; | 
|---|
|  | 249 | BoundaryTestPair = BoundaryPoints[axis].insert( BoundariesPair (angle, DistanceNrPair (radius, Walker) ) ); | 
|---|
|  | 250 | if (BoundaryTestPair.second) { // successfully inserted | 
|---|
|  | 251 | } else { // same point exists, check first r, then distance of original vectors to center of gravity | 
|---|
|  | 252 | *out << Verbose(2) << "Encountered two vectors whose projection onto axis " << axis << " is equal: " << endl; | 
|---|
|  | 253 | *out << Verbose(2) << "Present vector: "; | 
|---|
|  | 254 | BoundaryTestPair.first->second.second->x.Output(out); | 
|---|
|  | 255 | *out << endl; | 
|---|
|  | 256 | *out << Verbose(2) << "New vector: "; | 
|---|
|  | 257 | Walker->x.Output(out); | 
|---|
|  | 258 | *out << endl; | 
|---|
|  | 259 | double tmp = ProjectedVector.Norm(); | 
|---|
|  | 260 | if (tmp > BoundaryTestPair.first->second.first) { | 
|---|
|  | 261 | BoundaryTestPair.first->second.first = tmp; | 
|---|
|  | 262 | BoundaryTestPair.first->second.second = Walker; | 
|---|
|  | 263 | *out << Verbose(2) << "Keeping new vector." << endl; | 
|---|
|  | 264 | } else if (tmp == BoundaryTestPair.first->second.first) { | 
|---|
|  | 265 | if (BoundaryTestPair.first->second.second->x.ScalarProduct(&BoundaryTestPair.first->second.second->x) < Walker->x.ScalarProduct(&Walker->x)) { // Norm() does a sqrt, which makes it a lot slower | 
|---|
|  | 266 | BoundaryTestPair.first->second.second = Walker; | 
|---|
|  | 267 | *out << Verbose(2) << "Keeping new vector." << endl; | 
|---|
|  | 268 | } else { | 
|---|
|  | 269 | *out << Verbose(2) << "Keeping present vector." << endl; | 
|---|
|  | 270 | } | 
|---|
|  | 271 | } else { | 
|---|
|  | 272 | *out << Verbose(2) << "Keeping present vector." << endl; | 
|---|
|  | 273 | } | 
|---|
|  | 274 | } | 
|---|
|  | 275 | } | 
|---|
|  | 276 | // printing all inserted for debugging | 
|---|
|  | 277 | //    { | 
|---|
|  | 278 | //      *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl; | 
|---|
|  | 279 | //      int i=0; | 
|---|
|  | 280 | //      for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) { | 
|---|
|  | 281 | //        if (runner != BoundaryPoints[axis].begin()) | 
|---|
|  | 282 | //          *out << ", " << i << ": " << *runner->second.second; | 
|---|
|  | 283 | //        else | 
|---|
|  | 284 | //          *out << i << ": " << *runner->second.second; | 
|---|
|  | 285 | //        i++; | 
|---|
|  | 286 | //      } | 
|---|
|  | 287 | //      *out << endl; | 
|---|
|  | 288 | //    } | 
|---|
|  | 289 | // 3c. throw out points whose distance is less than the mean of left and right neighbours | 
|---|
|  | 290 | bool flag = false; | 
|---|
|  | 291 | do { // do as long as we still throw one out per round | 
|---|
|  | 292 | *out << Verbose(1) << "Looking for candidates to kick out by convex condition ... " << endl; | 
|---|
|  | 293 | flag = false; | 
|---|
|  | 294 | Boundaries::iterator left = BoundaryPoints[axis].end(); | 
|---|
|  | 295 | Boundaries::iterator right = BoundaryPoints[axis].end(); | 
|---|
|  | 296 | for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) { | 
|---|
|  | 297 | // set neighbours correctly | 
|---|
|  | 298 | if (runner == BoundaryPoints[axis].begin()) { | 
|---|
|  | 299 | left = BoundaryPoints[axis].end(); | 
|---|
|  | 300 | } else { | 
|---|
|  | 301 | left = runner; | 
|---|
|  | 302 | } | 
|---|
|  | 303 | left--; | 
|---|
|  | 304 | right = runner; | 
|---|
|  | 305 | right++; | 
|---|
|  | 306 | if (right == BoundaryPoints[axis].end()) { | 
|---|
|  | 307 | right = BoundaryPoints[axis].begin(); | 
|---|
|  | 308 | } | 
|---|
|  | 309 | // check distance | 
|---|
|  | 310 |  | 
|---|
|  | 311 | // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector) | 
|---|
|  | 312 | { | 
|---|
|  | 313 | vector SideA, SideB, SideC, SideH; | 
|---|
|  | 314 | SideA.CopyVector(&left->second.second->x); | 
|---|
|  | 315 | SideA.ProjectOntoPlane(&AxisVector); | 
|---|
|  | 316 | //          *out << "SideA: "; | 
|---|
|  | 317 | //          SideA.Output(out); | 
|---|
|  | 318 | //          *out << endl; | 
|---|
|  | 319 |  | 
|---|
|  | 320 | SideB.CopyVector(&right->second.second->x); | 
|---|
|  | 321 | SideB.ProjectOntoPlane(&AxisVector); | 
|---|
|  | 322 | //          *out << "SideB: "; | 
|---|
|  | 323 | //          SideB.Output(out); | 
|---|
|  | 324 | //          *out << endl; | 
|---|
|  | 325 |  | 
|---|
|  | 326 | SideC.CopyVector(&left->second.second->x); | 
|---|
|  | 327 | SideC.SubtractVector(&right->second.second->x); | 
|---|
|  | 328 | SideC.ProjectOntoPlane(&AxisVector); | 
|---|
|  | 329 | //          *out << "SideC: "; | 
|---|
|  | 330 | //          SideC.Output(out); | 
|---|
|  | 331 | //          *out << endl; | 
|---|
|  | 332 |  | 
|---|
|  | 333 | SideH.CopyVector(&runner->second.second->x); | 
|---|
|  | 334 | SideH.ProjectOntoPlane(&AxisVector); | 
|---|
|  | 335 | //          *out << "SideH: "; | 
|---|
|  | 336 | //          SideH.Output(out); | 
|---|
|  | 337 | //          *out << endl; | 
|---|
|  | 338 |  | 
|---|
|  | 339 | // calculate each length | 
|---|
|  | 340 | double a = SideA.Norm(); | 
|---|
|  | 341 | //double b = SideB.Norm(); | 
|---|
|  | 342 | //double c = SideC.Norm(); | 
|---|
|  | 343 | double h = SideH.Norm(); | 
|---|
|  | 344 | // calculate the angles | 
|---|
|  | 345 | double alpha = SideA.Angle(&SideH); | 
|---|
|  | 346 | double beta = SideA.Angle(&SideC); | 
|---|
|  | 347 | double gamma = SideB.Angle(&SideH); | 
|---|
|  | 348 | double delta = SideC.Angle(&SideH); | 
|---|
|  | 349 | double MinDistance = a * sin(beta)/(sin(delta)) * (((alpha < M_PI/2.) || (gamma < M_PI/2.)) ? 1. : -1.); | 
|---|
|  | 350 | //          *out << Verbose(2) << " I calculated: a = " << a << ", h = " << h << ", beta(" << left->second.second->Name << "," << left->second.second->Name << "-" << right->second.second->Name << ") = " << beta << ", delta(" << left->second.second->Name << "," << runner->second.second->Name << ") = " << delta << ", Min = " << MinDistance << "." << endl; | 
|---|
|  | 351 | //*out << Verbose(1) << "Checking CoG distance of runner " << *runner->second.second << " " << h << " against triangle's side length spanned by (" << *left->second.second << "," << *right->second.second << ") of " << MinDistance << "." << endl; | 
|---|
|  | 352 | if ((fabs(h/fabs(h) - MinDistance/fabs(MinDistance)) < MYEPSILON) && (h <  MinDistance)) { | 
|---|
|  | 353 | // throw out point | 
|---|
|  | 354 | //*out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl; | 
|---|
|  | 355 | BoundaryPoints[axis].erase(runner); | 
|---|
|  | 356 | flag = true; | 
|---|
|  | 357 | } | 
|---|
|  | 358 | } | 
|---|
|  | 359 | } | 
|---|
|  | 360 | } while (flag); | 
|---|
|  | 361 | } | 
|---|
|  | 362 | return BoundaryPoints; | 
|---|
|  | 363 | }; | 
|---|
|  | 364 |  | 
|---|
|  | 365 | /** Determines greatest diameters of a cluster defined by its convex envelope. | 
|---|
|  | 366 | * Looks at lines parallel to one axis and where they intersect on the projected planes | 
|---|
|  | 367 | * \param *out output stream for debugging | 
|---|
|  | 368 | * \param *BoundaryPoints NDIM set of boundary points defining the convex envelope on each projected plane | 
|---|
|  | 369 | * \param IsAngstroem whether we have angstroem or atomic units | 
|---|
|  | 370 | * \return NDIM array of the diameters | 
|---|
|  | 371 | */ | 
|---|
|  | 372 | double * GetDiametersOfCluster(ofstream *out, Boundaries *BoundaryPoints, bool IsAngstroem) | 
|---|
|  | 373 | { | 
|---|
|  | 374 | // determine biggest "diameter" of cluster for each axis | 
|---|
|  | 375 | Boundaries::iterator Neighbour, OtherNeighbour; | 
|---|
|  | 376 | double *GreatestDiameter = new double[NDIM]; | 
|---|
|  | 377 | for(int i=0;i<NDIM;i++) | 
|---|
|  | 378 | GreatestDiameter[i] = 0.; | 
|---|
|  | 379 | double OldComponent, tmp, w1, w2; | 
|---|
|  | 380 | vector DistanceVector, OtherVector; | 
|---|
|  | 381 | int component, Othercomponent; | 
|---|
|  | 382 | for(int axis=0;axis<NDIM;axis++) { // regard each projected plane | 
|---|
|  | 383 | //*out << Verbose(1) << "Current axis is " << axis << "." << endl; | 
|---|
|  | 384 | for (int j=0;j<2;j++) { // and for both axis on the current plane | 
|---|
|  | 385 | component = (axis+j+1)%NDIM; | 
|---|
|  | 386 | Othercomponent = (axis+1+((j+1) & 1))%NDIM; | 
|---|
|  | 387 | //*out << Verbose(1) << "Current component is " << component << ", Othercomponent is " << Othercomponent << "." << endl; | 
|---|
|  | 388 | for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) { | 
|---|
|  | 389 | //*out << Verbose(2) << "Current runner is " << *(runner->second.second) << "." << endl; | 
|---|
|  | 390 | // seek for the neighbours pair where the Othercomponent sign flips | 
|---|
|  | 391 | Neighbour = runner; | 
|---|
|  | 392 | Neighbour++; | 
|---|
|  | 393 | if (Neighbour == BoundaryPoints[axis].end())  // make it wrap around | 
|---|
|  | 394 | Neighbour = BoundaryPoints[axis].begin(); | 
|---|
|  | 395 | DistanceVector.CopyVector(&runner->second.second->x); | 
|---|
|  | 396 | DistanceVector.SubtractVector(&Neighbour->second.second->x); | 
|---|
|  | 397 | do {  // seek for neighbour pair where it flips | 
|---|
|  | 398 | OldComponent = DistanceVector.x[Othercomponent]; | 
|---|
|  | 399 | Neighbour++; | 
|---|
|  | 400 | if (Neighbour == BoundaryPoints[axis].end())  // make it wrap around | 
|---|
|  | 401 | Neighbour = BoundaryPoints[axis].begin(); | 
|---|
|  | 402 | DistanceVector.CopyVector(&runner->second.second->x); | 
|---|
|  | 403 | DistanceVector.SubtractVector(&Neighbour->second.second->x); | 
|---|
|  | 404 | //*out << Verbose(3) << "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << "." << endl; | 
|---|
|  | 405 | } while ((runner != Neighbour) && ( fabs( OldComponent/fabs(OldComponent) - DistanceVector.x[Othercomponent]/fabs(DistanceVector.x[Othercomponent]) ) < MYEPSILON)); // as long as sign does not flip | 
|---|
|  | 406 | if (runner != Neighbour) { | 
|---|
|  | 407 | OtherNeighbour = Neighbour; | 
|---|
|  | 408 | if (OtherNeighbour == BoundaryPoints[axis].begin())  // make it wrap around | 
|---|
|  | 409 | OtherNeighbour = BoundaryPoints[axis].end(); | 
|---|
|  | 410 | OtherNeighbour--; | 
|---|
|  | 411 | //*out << Verbose(2) << "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << "." << endl; | 
|---|
|  | 412 | // now we have found the pair: Neighbour and OtherNeighbour | 
|---|
|  | 413 | OtherVector.CopyVector(&runner->second.second->x); | 
|---|
|  | 414 | OtherVector.SubtractVector(&OtherNeighbour->second.second->x); | 
|---|
|  | 415 | //*out << Verbose(2) << "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << "." << endl; | 
|---|
|  | 416 | //*out << Verbose(2) << "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << "." << endl; | 
|---|
|  | 417 | // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour | 
|---|
|  | 418 | w1 = fabs(OtherVector.x[Othercomponent]); | 
|---|
|  | 419 | w2 = fabs(DistanceVector.x[Othercomponent]); | 
|---|
|  | 420 | tmp = fabs((w1*DistanceVector.x[component] + w2*OtherVector.x[component])/(w1+w2)); | 
|---|
|  | 421 | // mark if it has greater diameter | 
|---|
|  | 422 | //*out << Verbose(2) << "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << "." << endl; | 
|---|
|  | 423 | GreatestDiameter[component] = (GreatestDiameter[component] > tmp) ? GreatestDiameter[component] : tmp; | 
|---|
|  | 424 | } //else | 
|---|
|  | 425 | //*out << Verbose(2) << "Saw no sign flip, probably top or bottom node." << endl; | 
|---|
|  | 426 | } | 
|---|
|  | 427 | } | 
|---|
|  | 428 | } | 
|---|
|  | 429 | *out << Verbose(0) << "RESULT: The biggest diameters are " << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and " << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "." << endl; | 
|---|
|  | 430 |  | 
|---|
|  | 431 | return GreatestDiameter; | 
|---|
|  | 432 | }; | 
|---|
|  | 433 |  | 
|---|
|  | 434 |  | 
|---|
|  | 435 | /** Determines the volume of a cluster. | 
|---|
|  | 436 | * Determines first the convex envelope, then tesselates it and calculates its volume. | 
|---|
|  | 437 | * \param *out output stream for debugging | 
|---|
|  | 438 | * \param *configuration needed for path to store convex envelope file | 
|---|
|  | 439 | * \param *mol molecule structure representing the cluster | 
|---|
|  | 440 | */ | 
|---|
|  | 441 | double VolumeOfConvexEnvelope(ofstream *out, config *configuration, molecule *mol) | 
|---|
|  | 442 | { | 
|---|
|  | 443 | bool IsAngstroem = configuration->GetIsAngstroem(); | 
|---|
|  | 444 | atom *Walker = NULL; | 
|---|
|  | 445 | struct Tesselation *TesselStruct = new Tesselation; | 
|---|
|  | 446 | Boundaries *BoundaryPoints = NULL; | 
|---|
|  | 447 |  | 
|---|
|  | 448 | // 1. calculate center of gravity | 
|---|
|  | 449 | *out << endl; | 
|---|
|  | 450 | vector *CenterOfGravity = mol->DetermineCenterOfGravity(out); | 
|---|
|  | 451 |  | 
|---|
|  | 452 | // 2. translate all points into CoG | 
|---|
|  | 453 | *out << Verbose(1) << "Translating system to Center of Gravity." << endl; | 
|---|
|  | 454 | Walker = mol->start; | 
|---|
|  | 455 | while (Walker->next != mol->end) { | 
|---|
|  | 456 | Walker = Walker->next; | 
|---|
|  | 457 | Walker->x.Translate(CenterOfGravity); | 
|---|
|  | 458 | } | 
|---|
|  | 459 |  | 
|---|
|  | 460 | // 3. Find all points on the boundary | 
|---|
|  | 461 | BoundaryPoints = GetBoundaryPoints(out, mol); | 
|---|
|  | 462 |  | 
|---|
|  | 463 | // 3d. put into boundary set only those points appearing in each of the NDIM sets | 
|---|
|  | 464 | int *AtomList = new int[mol->AtomCount]; | 
|---|
|  | 465 | for (int j=0; j<mol->AtomCount; j++) // reset list | 
|---|
|  | 466 | AtomList[j] = 0; | 
|---|
|  | 467 | for (int axis=0; axis<NDIM; axis++)  {  // fill list when it's on the boundary | 
|---|
|  | 468 | for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) { | 
|---|
|  | 469 | AtomList[runner->second.second->nr]++; | 
|---|
|  | 470 | } | 
|---|
|  | 471 | } | 
|---|
|  | 472 | for (int axis=0; axis<NDIM; axis++)  { | 
|---|
|  | 473 | for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) { | 
|---|
|  | 474 | if (AtomList[runner->second.second->nr] < 1) { | 
|---|
|  | 475 | *out << Verbose(1) << "Throwing especially out " << *runner->second.second << " in axial projection of axis " << axis << "." << endl; | 
|---|
|  | 476 | BoundaryPoints[axis].erase(runner); | 
|---|
|  | 477 | } | 
|---|
|  | 478 | } | 
|---|
|  | 479 | } | 
|---|
|  | 480 | delete[](AtomList); | 
|---|
|  | 481 |  | 
|---|
|  | 482 | // 4a. fill the boundary point list | 
|---|
|  | 483 | Walker = mol->start; | 
|---|
|  | 484 | while (Walker->next != mol->end) { | 
|---|
|  | 485 | Walker = Walker->next; | 
|---|
|  | 486 | if (AtomList[Walker->nr] > 0) { | 
|---|
|  | 487 | TesselStruct->AddPoint(Walker); | 
|---|
|  | 488 | } | 
|---|
|  | 489 | } | 
|---|
|  | 490 |  | 
|---|
|  | 491 | *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl; | 
|---|
|  | 492 | // now we have the whole set of edge points in the BoundaryList | 
|---|
|  | 493 |  | 
|---|
|  | 494 |  | 
|---|
|  | 495 | // listing for debugging | 
|---|
|  | 496 | //  *out << Verbose(1) << "Listing PointsOnBoundary:"; | 
|---|
|  | 497 | //  for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) { | 
|---|
|  | 498 | //    *out << " " << *runner->second; | 
|---|
|  | 499 | //  } | 
|---|
|  | 500 | //  *out << endl; | 
|---|
|  | 501 |  | 
|---|
|  | 502 | // 4b. guess starting triangle | 
|---|
|  | 503 | TesselStruct->GuessStartingTriangle(out); | 
|---|
|  | 504 |  | 
|---|
|  | 505 | // 5. go through all lines, that are not yet part of two triangles (only of one so far) | 
|---|
|  | 506 | TesselStruct->TesselateOnBoundary(out, configuration, mol); | 
|---|
|  | 507 |  | 
|---|
|  | 508 | *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundaryCount << " triangles with " << TesselStruct->LinesOnBoundaryCount << " lines and " << TesselStruct->PointsOnBoundaryCount << " points." << endl; | 
|---|
|  | 509 |  | 
|---|
|  | 510 | // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes | 
|---|
|  | 511 | *out << Verbose(1) << "Calculating the volume of the pyramids formed out of triangles and center of gravity." << endl; | 
|---|
|  | 512 | double volume = 0.; | 
|---|
|  | 513 | double PyramidVolume = 0.; | 
|---|
|  | 514 | double G,h; | 
|---|
|  | 515 | vector x,y; | 
|---|
|  | 516 | double a,b,c; | 
|---|
|  | 517 | for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++) { // go through every triangle, calculate volume of its pyramid with CoG as peak | 
|---|
|  | 518 | x.CopyVector(&runner->second->endpoints[0]->node->x); | 
|---|
|  | 519 | x.SubtractVector(&runner->second->endpoints[1]->node->x); | 
|---|
|  | 520 | y.CopyVector(&runner->second->endpoints[0]->node->x); | 
|---|
|  | 521 | y.SubtractVector(&runner->second->endpoints[2]->node->x); | 
|---|
|  | 522 | a = sqrt(runner->second->endpoints[0]->node->x.Distance(&runner->second->endpoints[1]->node->x)); | 
|---|
|  | 523 | b = sqrt(runner->second->endpoints[0]->node->x.Distance(&runner->second->endpoints[2]->node->x)); | 
|---|
|  | 524 | c = sqrt(runner->second->endpoints[2]->node->x.Distance(&runner->second->endpoints[1]->node->x)); | 
|---|
|  | 525 | G =  sqrt( ( (a*a+b*b+c*c)*(a*a+b*b+c*c) - 2*(a*a*a*a + b*b*b*b + c*c*c*c) )/16.); // area of tesselated triangle | 
|---|
|  | 526 | x.MakeNormalVector(&runner->second->endpoints[0]->node->x, &runner->second->endpoints[1]->node->x, &runner->second->endpoints[2]->node->x); | 
|---|
|  | 527 | x.Scale(runner->second->endpoints[1]->node->x.Projection(&x)); | 
|---|
|  | 528 | h = x.Norm(); // distance of CoG to triangle | 
|---|
|  | 529 | PyramidVolume = (1./3.) * G * h;    // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak) | 
|---|
|  | 530 | *out << Verbose(2) << "Area of triangle is " << G << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is " << h << " and the volume is " << PyramidVolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; | 
|---|
|  | 531 | volume += PyramidVolume; | 
|---|
|  | 532 | } | 
|---|
|  | 533 | *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10) << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; | 
|---|
|  | 534 |  | 
|---|
|  | 535 |  | 
|---|
|  | 536 | // 7. translate all points back from CoG | 
|---|
|  | 537 | *out << Verbose(1) << "Translating system back from Center of Gravity." << endl; | 
|---|
|  | 538 | CenterOfGravity->Scale(-1); | 
|---|
|  | 539 | Walker = mol->start; | 
|---|
|  | 540 | while (Walker->next != mol->end) { | 
|---|
|  | 541 | Walker = Walker->next; | 
|---|
|  | 542 | Walker->x.Translate(CenterOfGravity); | 
|---|
|  | 543 | } | 
|---|
|  | 544 |  | 
|---|
|  | 545 | // free reference lists | 
|---|
|  | 546 |  | 
|---|
|  | 547 | return volume; | 
|---|
|  | 548 | }; | 
|---|
|  | 549 |  | 
|---|
|  | 550 |  | 
|---|
|  | 551 | /** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density. | 
|---|
|  | 552 | * \param *out output stream for debugging | 
|---|
|  | 553 | * \param *configuration needed for path to store convex envelope file | 
|---|
|  | 554 | * \param *mol molecule structure representing the cluster | 
|---|
|  | 555 | * \param clustervolume volume of the convex envelope cluster, \sa VolumeOfConvexEnvelope() | 
|---|
|  | 556 | * \param celldensity desired average density in final cell | 
|---|
|  | 557 | * \param GreatestDiameter[]  greatest diameter of the cluster, \sa GetDiametersOfCluster() | 
|---|
|  | 558 | */ | 
|---|
|  | 559 | void CreateClustersinWater(ofstream *out, config *configuration, molecule *mol, double clustervolume, double celldensity, double GreatestDiameter[NDIM]) | 
|---|
|  | 560 | { | 
|---|
|  | 561 | bool IsAngstroem = configuration->GetIsAngstroem(); | 
|---|
|  | 562 | // sum up the atomic masses | 
|---|
|  | 563 | double totalmass = 0.; | 
|---|
|  | 564 | atom *Walker = mol->start; | 
|---|
|  | 565 | while (Walker->next != mol->end) { | 
|---|
|  | 566 | Walker = Walker->next; | 
|---|
|  | 567 | totalmass += Walker->type->mass; | 
|---|
|  | 568 | } | 
|---|
|  | 569 | *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10) << totalmass << " atomicmassunit." << endl; | 
|---|
|  | 570 |  | 
|---|
|  | 571 | *out << Verbose(0) << "RESULT: The average density is " << setprecision(10) << totalmass/clustervolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; | 
|---|
|  | 572 |  | 
|---|
|  | 573 | // solve cubic polynomial | 
|---|
|  | 574 | *out << Verbose(1) << "Solving equidistant suspension in water problem ..." << endl; | 
|---|
|  | 575 | double cellvolume; | 
|---|
|  | 576 | if (IsAngstroem) | 
|---|
|  | 577 | cellvolume = (4*totalmass/SOLVENTDENSITY_A - (totalmass/clustervolume))/(celldensity-1); | 
|---|
|  | 578 | else | 
|---|
|  | 579 | cellvolume = (4*totalmass/SOLVENTDENSITY_a0 - (totalmass/clustervolume))/(celldensity-1); | 
|---|
|  | 580 | *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; | 
|---|
|  | 581 | double minimumvolume = 4*(GreatestDiameter[0]*GreatestDiameter[1]*GreatestDiameter[2]); | 
|---|
|  | 582 | *out << Verbose(1) << "Minimum volume of the convex envelope contained in a rectangular box is " << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; | 
|---|
|  | 583 | if (minimumvolume < cellvolume) | 
|---|
|  | 584 | cerr << Verbose(0) << "ERROR: the containing box already has a greater volume than the envisaged cell volume!" << endl; | 
|---|
|  | 585 | double  a = 4*(GreatestDiameter[0]+GreatestDiameter[1]+GreatestDiameter[2]); | 
|---|
|  | 586 | double b = 4*(GreatestDiameter[0]*GreatestDiameter[1] + GreatestDiameter[0]*GreatestDiameter[2] + GreatestDiameter[1]*GreatestDiameter[2]); | 
|---|
|  | 587 | double c = minimumvolume - cellvolume; | 
|---|
|  | 588 | double x0 = 0.,x1 = 0.,x2 = 0.; | 
|---|
|  | 589 | if (gsl_poly_solve_cubic(a,b,c,&x0,&x1,&x2) == 1) // either 1 or 3 on return | 
|---|
|  | 590 | *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0 << " ." << endl; | 
|---|
|  | 591 | else { | 
|---|
|  | 592 | *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0 << " and " << x1 << " and " << x2 << " ." << endl; | 
|---|
|  | 593 | x0 = x2;  // sorted in ascending order | 
|---|
|  | 594 | } | 
|---|
|  | 595 |  | 
|---|
|  | 596 | a = 2 * (x0 + GreatestDiameter[0]); | 
|---|
|  | 597 | b = 2 * (x0 + GreatestDiameter[1]); | 
|---|
|  | 598 | c = (x0 + GreatestDiameter[2]); | 
|---|
|  | 599 | *out << Verbose(0) << "RESULT: The resulting cell dimensions are: " << a << " and " << b << " and " << c << " with total volume of " << a*b*c << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl; | 
|---|
|  | 600 | }; | 
|---|
|  | 601 |  | 
|---|
|  | 602 |  | 
|---|
|  | 603 | // =========================================================== class TESSELATION =========================================== | 
|---|
|  | 604 |  | 
|---|
|  | 605 | /** Constructor of class Tesselation. | 
|---|
|  | 606 | */ | 
|---|
|  | 607 | Tesselation::Tesselation() | 
|---|
|  | 608 | { | 
|---|
|  | 609 | PointsOnBoundaryCount = 0; | 
|---|
|  | 610 | LinesOnBoundaryCount = 0; | 
|---|
|  | 611 | TrianglesOnBoundaryCount = 0; | 
|---|
|  | 612 | }; | 
|---|
|  | 613 |  | 
|---|
|  | 614 | /** Constructor of class Tesselation. | 
|---|
|  | 615 | * We have to free all points, lines and triangles. | 
|---|
|  | 616 | */ | 
|---|
|  | 617 | Tesselation::~Tesselation() | 
|---|
|  | 618 | { | 
|---|
|  | 619 | for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner != TrianglesOnBoundary.end(); runner++) { | 
|---|
|  | 620 | delete(runner->second); | 
|---|
|  | 621 | } | 
|---|
|  | 622 | }; | 
|---|
|  | 623 |  | 
|---|
|  | 624 | /** Gueses first starting triangle of the convex envelope. | 
|---|
|  | 625 | * We guess the starting triangle by taking the smallest distance between two points and looking for a fitting third. | 
|---|
|  | 626 | * \param *out output stream for debugging | 
|---|
|  | 627 | * \param PointsOnBoundary set of boundary points defining the convex envelope of the cluster | 
|---|
|  | 628 | */ | 
|---|
|  | 629 | void Tesselation::GuessStartingTriangle(ofstream *out) | 
|---|
|  | 630 | { | 
|---|
|  | 631 | // 4b. create a starting triangle | 
|---|
|  | 632 | // 4b1. create all distances | 
|---|
|  | 633 | DistanceMultiMap DistanceMMap; | 
|---|
|  | 634 | double distance; | 
|---|
|  | 635 | for (PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) { | 
|---|
|  | 636 | for(PointMap::iterator sprinter = PointsOnBoundary.begin(); sprinter != PointsOnBoundary.end(); sprinter++) { | 
|---|
|  | 637 | if (runner->first < sprinter->first) { | 
|---|
|  | 638 | distance = runner->second->node->x.Distance(&sprinter->second->node->x); | 
|---|
|  | 639 | DistanceMMap.insert( DistanceMultiMapPair(distance, pair<PointMap::iterator, PointMap::iterator>(runner,sprinter) ) ); | 
|---|
|  | 640 | } | 
|---|
|  | 641 | } | 
|---|
|  | 642 | } | 
|---|
|  | 643 |  | 
|---|
|  | 644 | //    // listing distances | 
|---|
|  | 645 | //    *out << Verbose(1) << "Listing DistanceMMap:"; | 
|---|
|  | 646 | //    for(DistanceMultiMap::iterator runner = DistanceMMap.begin(); runner != DistanceMMap.end(); runner++) { | 
|---|
|  | 647 | //      *out << " " << runner->first << "(" << *runner->second.first->second << ", " << *runner->second.second->second << ")"; | 
|---|
|  | 648 | //    } | 
|---|
|  | 649 | //    *out << endl; | 
|---|
|  | 650 |  | 
|---|
|  | 651 | // 4b2. take three smallest distance that form a triangle | 
|---|
|  | 652 | // we take the smallest distance as the base line | 
|---|
|  | 653 | DistanceMultiMap::iterator baseline = DistanceMMap.begin(); | 
|---|
|  | 654 | BPS[0] = baseline->second.first->second; | 
|---|
|  | 655 | BPS[1] = baseline->second.second->second; | 
|---|
|  | 656 | BLS[0] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount); | 
|---|
|  | 657 |  | 
|---|
|  | 658 | // take the second smallest as the second base line | 
|---|
|  | 659 | DistanceMultiMap::iterator secondline = DistanceMMap.begin(); | 
|---|
|  | 660 | do { | 
|---|
|  | 661 | secondline++; | 
|---|
|  | 662 | } while (!( | 
|---|
|  | 663 | (BPS[0] == secondline->second.first->second) && (BPS[1] != secondline->second.second->second) || | 
|---|
|  | 664 | (BPS[0] == secondline->second.second->second) && (BPS[1] != secondline->second.first->second) || | 
|---|
|  | 665 | (BPS[1] == secondline->second.first->second) && (BPS[0] != secondline->second.second->second) || | 
|---|
|  | 666 | (BPS[1] == secondline->second.second->second) && (BPS[0] != secondline->second.first->second) | 
|---|
|  | 667 | )); | 
|---|
|  | 668 | BPS[0] = secondline->second.first->second; | 
|---|
|  | 669 | BPS[1] = secondline->second.second->second; | 
|---|
|  | 670 | BLS[1] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount); | 
|---|
|  | 671 |  | 
|---|
|  | 672 | // connection yields the third line (note: first and second endpoint are sorted!) | 
|---|
|  | 673 | if (baseline->second.first->second == secondline->second.first->second) { | 
|---|
|  | 674 | SetEndpointsOrdered(BPS, baseline->second.second->second, secondline->second.second->second); | 
|---|
|  | 675 | } else if (baseline->second.first->second == secondline->second.second->second) { | 
|---|
|  | 676 | SetEndpointsOrdered(BPS, baseline->second.second->second, secondline->second.first->second); | 
|---|
|  | 677 | } else if (baseline->second.second->second == secondline->second.first->second) { | 
|---|
|  | 678 | SetEndpointsOrdered(BPS, baseline->second.first->second, baseline->second.second->second); | 
|---|
|  | 679 | } else if (baseline->second.second->second == secondline->second.second->second) { | 
|---|
|  | 680 | SetEndpointsOrdered(BPS, baseline->second.first->second, baseline->second.first->second); | 
|---|
|  | 681 | } | 
|---|
|  | 682 | BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); | 
|---|
|  | 683 |  | 
|---|
|  | 684 | // 4b3. insert created triangle | 
|---|
|  | 685 | BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount); | 
|---|
|  | 686 | TrianglesOnBoundary.insert( TrianglePair(TrianglesOnBoundaryCount, BTS) ); | 
|---|
|  | 687 | TrianglesOnBoundaryCount++; | 
|---|
|  | 688 | for(int i=0;i<NDIM;i++) { | 
|---|
|  | 689 | LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BTS->lines[i]) ); | 
|---|
|  | 690 | LinesOnBoundaryCount++; | 
|---|
|  | 691 | } | 
|---|
|  | 692 |  | 
|---|
|  | 693 | *out << Verbose(1) << "Starting triangle is " << *BTS << "." << endl; | 
|---|
|  | 694 | }; | 
|---|
|  | 695 |  | 
|---|
|  | 696 |  | 
|---|
|  | 697 | /** Tesselates the convex envelope of a cluster from a single starting triangle. | 
|---|
|  | 698 | * The starting triangle is made out of three baselines. Each line in the final tesselated cluster may belong to at most | 
|---|
|  | 699 | * 2 triangles. Hence, we go through all current lines: | 
|---|
|  | 700 | * -# if the lines contains to only one triangle | 
|---|
|  | 701 | * -# We search all points in the boundary | 
|---|
|  | 702 | *    -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors | 
|---|
|  | 703 | *    -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to | 
|---|
|  | 704 | *       baseline in triangle plane pointing out of the triangle and normal vector of new triangle) | 
|---|
|  | 705 | *    -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount) | 
|---|
|  | 706 | * \param *out output stream for debugging | 
|---|
|  | 707 | * \param *configuration for IsAngstroem | 
|---|
|  | 708 | * \param *mol the cluster as a molecule structure | 
|---|
|  | 709 | */ | 
|---|
|  | 710 | void Tesselation::TesselateOnBoundary(ofstream *out, config *configuration, molecule *mol) | 
|---|
|  | 711 | { | 
|---|
|  | 712 | bool flag; | 
|---|
|  | 713 | PointMap::iterator winner; | 
|---|
|  | 714 | class BoundaryPointSet *peak = NULL; | 
|---|
|  | 715 | double SmallestAngle, TempAngle; | 
|---|
|  | 716 | vector NormalVector, VirtualNormalVector, CenterVector, TempVector, PropagationVector; | 
|---|
|  | 717 | LineMap::iterator LineChecker[2]; | 
|---|
|  | 718 | do { | 
|---|
|  | 719 | flag = false; | 
|---|
|  | 720 | for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline++) | 
|---|
|  | 721 | if (baseline->second->TrianglesCount == 1) { | 
|---|
|  | 722 | *out << Verbose(2) << "Current baseline is between " << *(baseline->second) << "." << endl; | 
|---|
|  | 723 | // 5a. go through each boundary point if not _both_ edges between either endpoint of the current line and this point exist (and belong to 2 triangles) | 
|---|
|  | 724 | SmallestAngle = M_PI; | 
|---|
|  | 725 | BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far | 
|---|
|  | 726 | // get peak point with respect to this base line's only triangle | 
|---|
|  | 727 | for(int i=0;i<3;i++) | 
|---|
|  | 728 | if ((BTS->endpoints[i] != baseline->second->endpoints[0]) && (BTS->endpoints[i] != baseline->second->endpoints[1])) | 
|---|
|  | 729 | peak = BTS->endpoints[i]; | 
|---|
|  | 730 | *out << Verbose(3) << " and has peak " << *peak << "." << endl; | 
|---|
|  | 731 | // normal vector of triangle | 
|---|
|  | 732 | BTS->GetNormalVector(NormalVector); | 
|---|
|  | 733 | *out << Verbose(4) << "NormalVector of base triangle is "; | 
|---|
|  | 734 | NormalVector.Output(out); | 
|---|
|  | 735 | *out << endl; | 
|---|
|  | 736 | // offset to center of triangle | 
|---|
|  | 737 | CenterVector.Zero(); | 
|---|
|  | 738 | for(int i=0;i<3;i++) | 
|---|
|  | 739 | CenterVector.AddVector(&BTS->endpoints[i]->node->x); | 
|---|
|  | 740 | CenterVector.Scale(1./3.); | 
|---|
|  | 741 | *out << Verbose(4) << "CenterVector of base triangle is "; | 
|---|
|  | 742 | CenterVector.Output(out); | 
|---|
|  | 743 | *out << endl; | 
|---|
|  | 744 | // vector in propagation direction (out of triangle) | 
|---|
|  | 745 | // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection) | 
|---|
|  | 746 | TempVector.CopyVector(&baseline->second->endpoints[0]->node->x); | 
|---|
|  | 747 | TempVector.SubtractVector(&baseline->second->endpoints[1]->node->x); | 
|---|
|  | 748 | PropagationVector.MakeNormalVector(&TempVector, &NormalVector); | 
|---|
|  | 749 | TempVector.CopyVector(&CenterVector); | 
|---|
|  | 750 | TempVector.SubtractVector(&baseline->second->endpoints[0]->node->x);  // TempVector is vector on triangle plane pointing from one baseline egde towards center! | 
|---|
|  | 751 | //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl; | 
|---|
|  | 752 | if (PropagationVector.Projection(&TempVector) > 0)  // make sure normal propagation vector points outward from baseline | 
|---|
|  | 753 | PropagationVector.Scale(-1.); | 
|---|
|  | 754 | *out << Verbose(4) << "PropagationVector of base triangle is "; | 
|---|
|  | 755 | PropagationVector.Output(out); | 
|---|
|  | 756 | *out << endl; | 
|---|
|  | 757 | winner = PointsOnBoundary.end(); | 
|---|
|  | 758 | for (PointMap::iterator target = PointsOnBoundary.begin(); target != PointsOnBoundary.end(); target++) | 
|---|
|  | 759 | if ((target->second != baseline->second->endpoints[0]) && (target->second != baseline->second->endpoints[1])) { // don't take the same endpoints | 
|---|
|  | 760 | *out << Verbose(3) << "Target point is " << *(target->second) << ":"; | 
|---|
|  | 761 | bool continueflag = true; | 
|---|
|  | 762 |  | 
|---|
|  | 763 | VirtualNormalVector.CopyVector(&baseline->second->endpoints[0]->node->x); | 
|---|
|  | 764 | VirtualNormalVector.AddVector(&baseline->second->endpoints[0]->node->x); | 
|---|
|  | 765 | VirtualNormalVector.Scale(-1./2.);   // points now to center of base line | 
|---|
|  | 766 | VirtualNormalVector.AddVector(&target->second->node->x); // points from center of base line to target | 
|---|
|  | 767 | TempAngle = VirtualNormalVector.Angle(&PropagationVector); | 
|---|
|  | 768 | continueflag = continueflag && (TempAngle < (M_PI/2.)); // no bends bigger than Pi/2 (90 degrees) | 
|---|
|  | 769 | if (!continueflag) { | 
|---|
|  | 770 | *out << Verbose(4) << "Angle between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", bad direction!" << endl; | 
|---|
|  | 771 | continue; | 
|---|
|  | 772 | } else | 
|---|
|  | 773 | *out << Verbose(4) << "Angle between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", good direction!" << endl; | 
|---|
|  | 774 | LineChecker[0] = baseline->second->endpoints[0]->lines.find(target->first); | 
|---|
|  | 775 | LineChecker[1] = baseline->second->endpoints[1]->lines.find(target->first); | 
|---|
|  | 776 | //            if (LineChecker[0] != baseline->second->endpoints[0]->lines.end()) | 
|---|
|  | 777 | //              *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl; | 
|---|
|  | 778 | //            else | 
|---|
|  | 779 | //              *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has no line to " << *(target->second) << " as endpoint." << endl; | 
|---|
|  | 780 | //            if (LineChecker[1] != baseline->second->endpoints[1]->lines.end()) | 
|---|
|  | 781 | //              *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl; | 
|---|
|  | 782 | //            else | 
|---|
|  | 783 | //              *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has no line to " << *(target->second) << " as endpoint." << endl; | 
|---|
|  | 784 | // check first endpoint (if any connecting line goes to target or at least not more than 1) | 
|---|
|  | 785 | continueflag = continueflag && (( (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) || (LineChecker[0]->second->TrianglesCount == 1))); | 
|---|
|  | 786 | if (!continueflag) { | 
|---|
|  | 787 | *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl; | 
|---|
|  | 788 | continue; | 
|---|
|  | 789 | } | 
|---|
|  | 790 | // check second endpoint (if any connecting line goes to target or at least not more than 1) | 
|---|
|  | 791 | continueflag = continueflag && (( (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) || (LineChecker[1]->second->TrianglesCount == 1))); | 
|---|
|  | 792 | if (!continueflag) { | 
|---|
|  | 793 | *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl; | 
|---|
|  | 794 | continue; | 
|---|
|  | 795 | } | 
|---|
|  | 796 | // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint) | 
|---|
|  | 797 | continueflag = continueflag && (!( | 
|---|
|  | 798 | ((LineChecker[0] != baseline->second->endpoints[0]->lines.end()) && (LineChecker[1] != baseline->second->endpoints[1]->lines.end()) | 
|---|
|  | 799 | && (GetCommonEndpoint(LineChecker[0]->second, LineChecker[1]->second) == peak)) | 
|---|
|  | 800 | )); | 
|---|
|  | 801 | if (!continueflag) { | 
|---|
|  | 802 | *out << Verbose(4) << "Current target is peak!" << endl; | 
|---|
|  | 803 | continue; | 
|---|
|  | 804 | } | 
|---|
|  | 805 | // in case NOT both were found | 
|---|
|  | 806 | if (continueflag) {  // create virtually this triangle, get its normal vector, calculate angle | 
|---|
|  | 807 | flag = true; | 
|---|
|  | 808 | VirtualNormalVector.MakeNormalVector(&baseline->second->endpoints[0]->node->x, &baseline->second->endpoints[1]->node->x, &target->second->node->x); | 
|---|
|  | 809 | // make it always point inward | 
|---|
|  | 810 | if (baseline->second->endpoints[0]->node->x.Projection(&VirtualNormalVector) > 0) | 
|---|
|  | 811 | VirtualNormalVector.Scale(-1.); | 
|---|
|  | 812 | // calculate angle | 
|---|
|  | 813 | TempAngle = NormalVector.Angle(&VirtualNormalVector); | 
|---|
|  | 814 | *out << Verbose(4) << "NormalVector is "; | 
|---|
|  | 815 | VirtualNormalVector.Output(out); | 
|---|
|  | 816 | *out << " and the angle is " << TempAngle << "." << endl; | 
|---|
|  | 817 | if (SmallestAngle > TempAngle) {  // set to new possible winner | 
|---|
|  | 818 | SmallestAngle = TempAngle; | 
|---|
|  | 819 | winner = target; | 
|---|
|  | 820 | } | 
|---|
|  | 821 | } | 
|---|
|  | 822 | } | 
|---|
|  | 823 | // 5b. The point of the above whose triangle has the greatest angle with the triangle the current line belongs to (it only belongs to one, remember!): New triangle | 
|---|
|  | 824 | if (winner != PointsOnBoundary.end()) { | 
|---|
|  | 825 | *out << Verbose(2) << "Winning target point is " << *(winner->second) << " with angle " << SmallestAngle << "." << endl; | 
|---|
|  | 826 | // create the lins of not yet present | 
|---|
|  | 827 | BLS[0] = baseline->second; | 
|---|
|  | 828 | // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles) | 
|---|
|  | 829 | LineChecker[0] = baseline->second->endpoints[0]->lines.find(winner->first); | 
|---|
|  | 830 | LineChecker[1] = baseline->second->endpoints[1]->lines.find(winner->first); | 
|---|
|  | 831 | if (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) { // create | 
|---|
|  | 832 | BPS[0] = baseline->second->endpoints[0]; | 
|---|
|  | 833 | BPS[1] = winner->second; | 
|---|
|  | 834 | BLS[1] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount); | 
|---|
|  | 835 | LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BLS[1]) ); | 
|---|
|  | 836 | LinesOnBoundaryCount++; | 
|---|
|  | 837 | } else | 
|---|
|  | 838 | BLS[1] = LineChecker[0]->second; | 
|---|
|  | 839 | if (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) { // create | 
|---|
|  | 840 | BPS[0] = baseline->second->endpoints[1]; | 
|---|
|  | 841 | BPS[1] = winner->second; | 
|---|
|  | 842 | BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount); | 
|---|
|  | 843 | LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BLS[2]) ); | 
|---|
|  | 844 | LinesOnBoundaryCount++; | 
|---|
|  | 845 | } else | 
|---|
|  | 846 | BLS[2] = LineChecker[1]->second; | 
|---|
|  | 847 | BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount); | 
|---|
|  | 848 | TrianglesOnBoundary.insert( TrianglePair(TrianglesOnBoundaryCount, BTS) ); | 
|---|
|  | 849 | TrianglesOnBoundaryCount++; | 
|---|
|  | 850 | } else { | 
|---|
|  | 851 | *out << Verbose(1) << "I could not determine a winner for this baseline " << *(baseline->second) << "." << endl; | 
|---|
|  | 852 | } | 
|---|
|  | 853 |  | 
|---|
|  | 854 | // 5d. If the set of lines is not yet empty, go to 5. and continue | 
|---|
|  | 855 | } else | 
|---|
|  | 856 | *out << Verbose(2) << "Baseline candidate " << *(baseline->second) << " has a triangle count of " << baseline->second->TrianglesCount << "." << endl; | 
|---|
|  | 857 | } while (flag); | 
|---|
|  | 858 |  | 
|---|
|  | 859 | stringstream line; | 
|---|
|  | 860 | line << configuration->configpath << "/" << CONVEXENVELOPE; | 
|---|
|  | 861 | *out << Verbose(1) << "Storing convex envelope in tecplot data file " << line.str() << "." << endl; | 
|---|
|  | 862 | ofstream output(line.str().c_str()); | 
|---|
|  | 863 | output << "TITLE = \"3D CONVEX SHELL\"" << endl; | 
|---|
|  | 864 | output << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl; | 
|---|
|  | 865 | output << "ZONE T=\"TRIANGLES\", N=" << PointsOnBoundaryCount << ", E=" << TrianglesOnBoundaryCount << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl; | 
|---|
|  | 866 | int *LookupList = new int[mol->AtomCount]; | 
|---|
|  | 867 | for (int i=0;i<mol->AtomCount;i++) | 
|---|
|  | 868 | LookupList[i] = -1; | 
|---|
|  | 869 |  | 
|---|
|  | 870 | // print atom coordinates | 
|---|
|  | 871 | *out << Verbose(2) << "The following triangles were created:"; | 
|---|
|  | 872 | int Counter = 1; | 
|---|
|  | 873 | atom *Walker = NULL; | 
|---|
|  | 874 | for (PointMap::iterator target = PointsOnBoundary.begin(); target != PointsOnBoundary.end(); target++) { | 
|---|
|  | 875 | Walker = target->second->node; | 
|---|
|  | 876 | LookupList[Walker->nr] = Counter++; | 
|---|
|  | 877 | output << Walker->x.x[0] << " " << Walker->x.x[1] << " " << Walker->x.x[2] << " " << endl; | 
|---|
|  | 878 | } | 
|---|
|  | 879 | output << endl; | 
|---|
|  | 880 | // print connectivity | 
|---|
|  | 881 | for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner != TrianglesOnBoundary.end(); runner++) { | 
|---|
|  | 882 | *out << " " << runner->second->endpoints[0]->node->Name << "<->" << runner->second->endpoints[1]->node->Name << "<->" << runner->second->endpoints[2]->node->Name; | 
|---|
|  | 883 | output << LookupList[runner->second->endpoints[0]->node->nr] << " " << LookupList[runner->second->endpoints[1]->node->nr] << " " << LookupList[runner->second->endpoints[2]->node->nr] << endl; | 
|---|
|  | 884 | } | 
|---|
|  | 885 | output.close(); | 
|---|
|  | 886 | delete[](LookupList); | 
|---|
|  | 887 | *out << endl; | 
|---|
|  | 888 | }; | 
|---|
|  | 889 |  | 
|---|
|  | 890 | /** Adds an atom to the tesselation::PointsOnBoundary list. | 
|---|
|  | 891 | * \param *Walker atom to add | 
|---|
|  | 892 | */ | 
|---|
|  | 893 | void Tesselation::AddPoint(atom *Walker) | 
|---|
|  | 894 | { | 
|---|
|  | 895 | BPS[0] = new class BoundaryPointSet(Walker); | 
|---|
|  | 896 | PointsOnBoundary.insert( PointPair(Walker->nr, BPS[0]) ); | 
|---|
|  | 897 | PointsOnBoundaryCount++; | 
|---|
|  | 898 | }; | 
|---|