source: src/boundary.cpp@ 9a5bcd

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 9a5bcd was 2b4a40, checked in by Frederik Heber <heber@…>, 16 years ago

new version of Tesselation::GuessStartingTriangle() seems to fix problems

+ now, we find the starting triangle in the following manner (point = boundary point!):

  1. pick a point A
  2. for all unequal pairs B,C (not A), calculate AB2+BC2+AC2 and sort into ascending list
  3. Go through list, picking thus baseline B,C along with peak A of a candidate triangle
  4. check whether all other boundary points lie only on one side
  5. check whether no boundary point is inside the triangle
  6. If all successful, starting triangle is found With this procedure, the convex hull of all SiOHCa3 clusters are found perfectly.
  • Property mode set to 100644
File size: 48.3 KB
Line 
1#include "molecules.hpp"
2#include "boundary.hpp"
3
4// ======================================== Points on Boundary =================================
5
6BoundaryPointSet::BoundaryPointSet()
7{
8 LinesCount = 0;
9 Nr = -1;
10};
11
12BoundaryPointSet::BoundaryPointSet(atom *Walker)
13{
14 node = Walker;
15 LinesCount = 0;
16 Nr = Walker->nr;
17};
18
19BoundaryPointSet::~BoundaryPointSet()
20{
21 cout << Verbose(5) << "Erasing point nr. " << Nr << "." << endl;
22 node = NULL;
23};
24
25void 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
36ostream & operator << (ostream &ost, BoundaryPointSet &a)
37{
38 ost << "[" << a.Nr << "|" << a.node->Name << "]";
39 return ost;
40};
41
42// ======================================== Lines on Boundary =================================
43
44BoundaryLineSet::BoundaryLineSet()
45{
46 for (int i=0;i<2;i++)
47 endpoints[i] = NULL;
48 TrianglesCount = 0;
49 Nr = -1;
50};
51
52BoundaryLineSet::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
66BoundaryLineSet::~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
81void 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
88ostream & 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
97BoundaryTriangleSet::BoundaryTriangleSet()
98{
99 for (int i=0;i<3;i++) {
100 endpoints[i] = NULL;
101 lines[i] = NULL;
102 }
103 Nr = -1;
104};
105
106BoundaryTriangleSet::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
138BoundaryTriangleSet::~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
153void 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
163ostream & 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/** Finds the endpoint two lines are sharing.
172 * \param *line1 first line
173 * \param *line2 second line
174 * \return point which is shared or NULL if none
175 */
176class BoundaryPointSet * GetCommonEndpoint(class BoundaryLineSet * line1, class BoundaryLineSet * line2)
177{
178 class BoundaryLineSet * lines[2] = {line1, line2};
179 class BoundaryPointSet *node = NULL;
180 map <int, class BoundaryPointSet * > OrderMap;
181 pair < map <int, class BoundaryPointSet * >::iterator, bool > OrderTest;
182 for(int i=0;i<2;i++) // for both lines
183 for (int j=0;j<2;j++) { // for both endpoints
184 OrderTest = OrderMap.insert ( pair <int, class BoundaryPointSet * >( lines[i]->endpoints[j]->Nr, lines[i]->endpoints[j]) );
185 if (!OrderTest.second) { // if insertion fails, we have common endpoint
186 node = OrderTest.first->second;
187 cout << Verbose(5) << "Common endpoint of lines " << *line1 << " and " << *line2 << " is: " << *node << "." << endl;
188 j=2;
189 i=2;
190 break;
191 }
192 }
193 return node;
194};
195
196/** Determines the boundary points of a cluster.
197 * Does a projection per axis onto the orthogonal plane, transforms into spherical coordinates, sorts them by the angle
198 * and looks at triples: if the middle has less a distance than the allowed maximum height of the triangle formed by the plane's
199 * center and first and last point in the triple, it is thrown out.
200 * \param *out output stream for debugging
201 * \param *mol molecule structure representing the cluster
202 */
203Boundaries * GetBoundaryPoints(ofstream *out, molecule *mol)
204{
205 atom *Walker = NULL;
206 PointMap PointsOnBoundary;
207 LineMap LinesOnBoundary;
208 TriangleMap TrianglesOnBoundary;
209
210 *out << Verbose(1) << "Finding all boundary points." << endl;
211 Boundaries *BoundaryPoints = new Boundaries [NDIM]; // first is alpha, second is (r, nr)
212 BoundariesTestPair BoundaryTestPair;
213 Vector AxisVector, AngleReferenceVector, AngleReferenceNormalVector;
214 double radius, angle;
215 // 3a. Go through every axis
216 for (int axis=0; axis<NDIM; axis++) {
217 AxisVector.Zero();
218 AngleReferenceVector.Zero();
219 AngleReferenceNormalVector.Zero();
220 AxisVector.x[axis] = 1.;
221 AngleReferenceVector.x[(axis+1)%NDIM] = 1.;
222 AngleReferenceNormalVector.x[(axis+2)%NDIM] = 1.;
223 // *out << Verbose(1) << "Axisvector is ";
224 // AxisVector.Output(out);
225 // *out << " and AngleReferenceVector is ";
226 // AngleReferenceVector.Output(out);
227 // *out << "." << endl;
228 // *out << " and AngleReferenceNormalVector is ";
229 // AngleReferenceNormalVector.Output(out);
230 // *out << "." << endl;
231 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
232 Walker = mol->start;
233 while (Walker->next != mol->end) {
234 Walker = Walker->next;
235 Vector ProjectedVector;
236 ProjectedVector.CopyVector(&Walker->x);
237 ProjectedVector.ProjectOntoPlane(&AxisVector);
238 // correct for negative side
239 //if (Projection(y) < 0)
240 //angle = 2.*M_PI - angle;
241 radius = ProjectedVector.Norm();
242 if (fabs(radius) > MYEPSILON)
243 angle = ProjectedVector.Angle(&AngleReferenceVector);
244 else
245 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
246
247 //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl;
248 if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0) {
249 angle = 2.*M_PI - angle;
250 }
251 //*out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): ";
252 //ProjectedVector.Output(out);
253 //*out << endl;
254 BoundaryTestPair = BoundaryPoints[axis].insert( BoundariesPair (angle, DistancePair (radius, Walker) ) );
255 if (BoundaryTestPair.second) { // successfully inserted
256 } else { // same point exists, check first r, then distance of original vectors to center of gravity
257 *out << Verbose(2) << "Encountered two vectors whose projection onto axis " << axis << " is equal: " << endl;
258 *out << Verbose(2) << "Present vector: ";
259 BoundaryTestPair.first->second.second->x.Output(out);
260 *out << endl;
261 *out << Verbose(2) << "New vector: ";
262 Walker->x.Output(out);
263 *out << endl;
264 double tmp = ProjectedVector.Norm();
265 if (tmp > BoundaryTestPair.first->second.first) {
266 BoundaryTestPair.first->second.first = tmp;
267 BoundaryTestPair.first->second.second = Walker;
268 *out << Verbose(2) << "Keeping new vector." << endl;
269 } else if (tmp == BoundaryTestPair.first->second.first) {
270 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
271 BoundaryTestPair.first->second.second = Walker;
272 *out << Verbose(2) << "Keeping new vector." << endl;
273 } else {
274 *out << Verbose(2) << "Keeping present vector." << endl;
275 }
276 } else {
277 *out << Verbose(2) << "Keeping present vector." << endl;
278 }
279 }
280 }
281 // printing all inserted for debugging
282 // {
283 // *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
284 // int i=0;
285 // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
286 // if (runner != BoundaryPoints[axis].begin())
287 // *out << ", " << i << ": " << *runner->second.second;
288 // else
289 // *out << i << ": " << *runner->second.second;
290 // i++;
291 // }
292 // *out << endl;
293 // }
294 // 3c. throw out points whose distance is less than the mean of left and right neighbours
295 bool flag = false;
296 do { // do as long as we still throw one out per round
297 *out << Verbose(1) << "Looking for candidates to kick out by convex condition ... " << endl;
298 flag = false;
299 Boundaries::iterator left = BoundaryPoints[axis].end();
300 Boundaries::iterator right = BoundaryPoints[axis].end();
301 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
302 // set neighbours correctly
303 if (runner == BoundaryPoints[axis].begin()) {
304 left = BoundaryPoints[axis].end();
305 } else {
306 left = runner;
307 }
308 left--;
309 right = runner;
310 right++;
311 if (right == BoundaryPoints[axis].end()) {
312 right = BoundaryPoints[axis].begin();
313 }
314 // check distance
315
316 // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)
317 {
318 Vector SideA, SideB, SideC, SideH;
319 SideA.CopyVector(&left->second.second->x);
320 SideA.ProjectOntoPlane(&AxisVector);
321 // *out << "SideA: ";
322 // SideA.Output(out);
323 // *out << endl;
324
325 SideB.CopyVector(&right->second.second->x);
326 SideB.ProjectOntoPlane(&AxisVector);
327 // *out << "SideB: ";
328 // SideB.Output(out);
329 // *out << endl;
330
331 SideC.CopyVector(&left->second.second->x);
332 SideC.SubtractVector(&right->second.second->x);
333 SideC.ProjectOntoPlane(&AxisVector);
334 // *out << "SideC: ";
335 // SideC.Output(out);
336 // *out << endl;
337
338 SideH.CopyVector(&runner->second.second->x);
339 SideH.ProjectOntoPlane(&AxisVector);
340 // *out << "SideH: ";
341 // SideH.Output(out);
342 // *out << endl;
343
344 // calculate each length
345 double a = SideA.Norm();
346 //double b = SideB.Norm();
347 //double c = SideC.Norm();
348 double h = SideH.Norm();
349 // calculate the angles
350 double alpha = SideA.Angle(&SideH);
351 double beta = SideA.Angle(&SideC);
352 double gamma = SideB.Angle(&SideH);
353 double delta = SideC.Angle(&SideH);
354 double MinDistance = a * sin(beta)/(sin(delta)) * (((alpha < M_PI/2.) || (gamma < M_PI/2.)) ? 1. : -1.);
355 // *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;
356 //*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;
357 if ((fabs(h/fabs(h) - MinDistance/fabs(MinDistance)) < MYEPSILON) && (h < MinDistance)) {
358 // throw out point
359 //*out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl;
360 BoundaryPoints[axis].erase(runner);
361 flag = true;
362 }
363 }
364 }
365 } while (flag);
366 }
367 return BoundaryPoints;
368};
369
370/** Determines greatest diameters of a cluster defined by its convex envelope.
371 * Looks at lines parallel to one axis and where they intersect on the projected planes
372 * \param *out output stream for debugging
373 * \param *BoundaryPoints NDIM set of boundary points defining the convex envelope on each projected plane
374 * \param *mol molecule structure representing the cluster
375 * \param IsAngstroem whether we have angstroem or atomic units
376 * \return NDIM array of the diameters
377 */
378double * GetDiametersOfCluster(ofstream *out, Boundaries *BoundaryPtr, molecule *mol, bool IsAngstroem)
379{
380 // get points on boundary of NULL was given as parameter
381 bool BoundaryFreeFlag = false;
382 Boundaries *BoundaryPoints = BoundaryPtr;
383 if (BoundaryPoints == NULL) {
384 BoundaryFreeFlag = true;
385 BoundaryPoints = GetBoundaryPoints(out, mol);
386 } else {
387 *out << Verbose(1) << "Using given boundary points set." << endl;
388 }
389
390 // determine biggest "diameter" of cluster for each axis
391 Boundaries::iterator Neighbour, OtherNeighbour;
392 double *GreatestDiameter = new double[NDIM];
393 for(int i=0;i<NDIM;i++)
394 GreatestDiameter[i] = 0.;
395 double OldComponent, tmp, w1, w2;
396 Vector DistanceVector, OtherVector;
397 int component, Othercomponent;
398 for(int axis=0;axis<NDIM;axis++) { // regard each projected plane
399 //*out << Verbose(1) << "Current axis is " << axis << "." << endl;
400 for (int j=0;j<2;j++) { // and for both axis on the current plane
401 component = (axis+j+1)%NDIM;
402 Othercomponent = (axis+1+((j+1) & 1))%NDIM;
403 //*out << Verbose(1) << "Current component is " << component << ", Othercomponent is " << Othercomponent << "." << endl;
404 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
405 //*out << Verbose(2) << "Current runner is " << *(runner->second.second) << "." << endl;
406 // seek for the neighbours pair where the Othercomponent sign flips
407 Neighbour = runner;
408 Neighbour++;
409 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
410 Neighbour = BoundaryPoints[axis].begin();
411 DistanceVector.CopyVector(&runner->second.second->x);
412 DistanceVector.SubtractVector(&Neighbour->second.second->x);
413 do { // seek for neighbour pair where it flips
414 OldComponent = DistanceVector.x[Othercomponent];
415 Neighbour++;
416 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
417 Neighbour = BoundaryPoints[axis].begin();
418 DistanceVector.CopyVector(&runner->second.second->x);
419 DistanceVector.SubtractVector(&Neighbour->second.second->x);
420 //*out << Verbose(3) << "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << "." << endl;
421 } while ((runner != Neighbour) && ( fabs( OldComponent/fabs(OldComponent) - DistanceVector.x[Othercomponent]/fabs(DistanceVector.x[Othercomponent]) ) < MYEPSILON)); // as long as sign does not flip
422 if (runner != Neighbour) {
423 OtherNeighbour = Neighbour;
424 if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around
425 OtherNeighbour = BoundaryPoints[axis].end();
426 OtherNeighbour--;
427 //*out << Verbose(2) << "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << "." << endl;
428 // now we have found the pair: Neighbour and OtherNeighbour
429 OtherVector.CopyVector(&runner->second.second->x);
430 OtherVector.SubtractVector(&OtherNeighbour->second.second->x);
431 //*out << Verbose(2) << "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << "." << endl;
432 //*out << Verbose(2) << "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << "." << endl;
433 // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour
434 w1 = fabs(OtherVector.x[Othercomponent]);
435 w2 = fabs(DistanceVector.x[Othercomponent]);
436 tmp = fabs((w1*DistanceVector.x[component] + w2*OtherVector.x[component])/(w1+w2));
437 // mark if it has greater diameter
438 //*out << Verbose(2) << "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << "." << endl;
439 GreatestDiameter[component] = (GreatestDiameter[component] > tmp) ? GreatestDiameter[component] : tmp;
440 } //else
441 //*out << Verbose(2) << "Saw no sign flip, probably top or bottom node." << endl;
442 }
443 }
444 }
445 *out << Verbose(0) << "RESULT: The biggest diameters are " << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and " << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "." << endl;
446
447 // free reference lists
448 if (BoundaryFreeFlag)
449 delete[](BoundaryPoints);
450
451 return GreatestDiameter;
452};
453
454
455/** Determines the volume of a cluster.
456 * Determines first the convex envelope, then tesselates it and calculates its volume.
457 * \param *out output stream for debugging
458 * \param *configuration needed for path to store convex envelope file
459 * \param *BoundaryPoints NDIM set of boundary points on the projected plane per axis, on return if desired
460 * \param *mol molecule structure representing the cluster
461 */
462double VolumeOfConvexEnvelope(ofstream *out, config *configuration, Boundaries *BoundaryPtr, molecule *mol)
463{
464 bool IsAngstroem = configuration->GetIsAngstroem();
465 atom *Walker = NULL;
466 struct Tesselation *TesselStruct = new Tesselation;
467 bool BoundaryFreeFlag = false;
468 Boundaries *BoundaryPoints = BoundaryPtr;
469 double volume = 0.;
470 double PyramidVolume = 0.;
471 double G,h;
472 Vector x,y;
473 double a,b,c;
474
475 // 1. calculate center of gravity
476 *out << endl;
477 Vector *CenterOfGravity = mol->DetermineCenterOfGravity(out);
478
479 // 2. translate all points into CoG
480 *out << Verbose(1) << "Translating system to Center of Gravity." << endl;
481 Walker = mol->start;
482 while (Walker->next != mol->end) {
483 Walker = Walker->next;
484 Walker->x.Translate(CenterOfGravity);
485 }
486
487 // 3. Find all points on the boundary
488 if (BoundaryPoints == NULL) {
489 BoundaryFreeFlag = true;
490 BoundaryPoints = GetBoundaryPoints(out, mol);
491 } else {
492 *out << Verbose(1) << "Using given boundary points set." << endl;
493 }
494
495 // 4. fill the boundary point list
496 for (int axis=0;axis<NDIM;axis++)
497 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
498 TesselStruct->AddPoint(runner->second.second);
499 }
500
501 *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl;
502 // now we have the whole set of edge points in the BoundaryList
503
504
505 // listing for debugging
506// *out << Verbose(1) << "Listing PointsOnBoundary:";
507// for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
508// *out << " " << *runner->second;
509// }
510// *out << endl;
511
512 // 5a. guess starting triangle
513 TesselStruct->GuessStartingTriangle(out);
514
515 // 5b. go through all lines, that are not yet part of two triangles (only of one so far)
516 TesselStruct->TesselateOnBoundary(out, configuration, mol);
517
518 *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundaryCount << " triangles with " << TesselStruct->LinesOnBoundaryCount << " lines and " << TesselStruct->PointsOnBoundaryCount << " points." << endl;
519
520 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
521 *out << Verbose(1) << "Calculating the volume of the pyramids formed out of triangles and center of gravity." << endl;
522 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
523 x.CopyVector(&runner->second->endpoints[0]->node->x);
524 x.SubtractVector(&runner->second->endpoints[1]->node->x);
525 y.CopyVector(&runner->second->endpoints[0]->node->x);
526 y.SubtractVector(&runner->second->endpoints[2]->node->x);
527 a = sqrt(runner->second->endpoints[0]->node->x.Distance(&runner->second->endpoints[1]->node->x));
528 b = sqrt(runner->second->endpoints[0]->node->x.Distance(&runner->second->endpoints[2]->node->x));
529 c = sqrt(runner->second->endpoints[2]->node->x.Distance(&runner->second->endpoints[1]->node->x));
530 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
531 x.MakeNormalVector(&runner->second->endpoints[0]->node->x, &runner->second->endpoints[1]->node->x, &runner->second->endpoints[2]->node->x);
532 x.Scale(runner->second->endpoints[1]->node->x.Projection(&x));
533 h = x.Norm(); // distance of CoG to triangle
534 PyramidVolume = (1./3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
535 *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;
536 volume += PyramidVolume;
537 }
538 *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10) << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
539
540
541 // 7. translate all points back from CoG
542 *out << Verbose(1) << "Translating system back from Center of Gravity." << endl;
543 CenterOfGravity->Scale(-1);
544 Walker = mol->start;
545 while (Walker->next != mol->end) {
546 Walker = Walker->next;
547 Walker->x.Translate(CenterOfGravity);
548 }
549
550 // free reference lists
551 if (BoundaryFreeFlag)
552 delete[](BoundaryPoints);
553
554 return volume;
555};
556
557
558/** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
559 * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
560 * \param *out output stream for debugging
561 * \param *configuration needed for path to store convex envelope file
562 * \param *mol molecule structure representing the cluster
563 * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead.
564 * \param celldensity desired average density in final cell
565 */
566void PrepareClustersinWater(ofstream *out, config *configuration, molecule *mol, double ClusterVolume, double celldensity)
567{
568 // transform to PAS
569 mol->PrincipalAxisSystem(out, true);
570
571 // some preparations beforehand
572 bool IsAngstroem = configuration->GetIsAngstroem();
573 Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol);
574 double clustervolume;
575 if (ClusterVolume == 0)
576 clustervolume = VolumeOfConvexEnvelope(out, configuration, BoundaryPoints, mol);
577 else
578 clustervolume = ClusterVolume;
579 double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, IsAngstroem);
580 Vector BoxLengths;
581 int repetition[NDIM] = {1, 1, 1};
582 int TotalNoClusters = 1;
583 for (int i=0;i<NDIM;i++)
584 TotalNoClusters *= repetition[i];
585
586 // sum up the atomic masses
587 double totalmass = 0.;
588 atom *Walker = mol->start;
589 while (Walker->next != mol->end) {
590 Walker = Walker->next;
591 totalmass += Walker->type->mass;
592 }
593 *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10) << totalmass << " atomicmassunit." << endl;
594
595 *out << Verbose(0) << "RESULT: The average density is " << setprecision(10) << totalmass/clustervolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
596
597 // solve cubic polynomial
598 *out << Verbose(1) << "Solving equidistant suspension in water problem ..." << endl;
599 double cellvolume;
600 if (IsAngstroem)
601 cellvolume = (TotalNoClusters*totalmass/SOLVENTDENSITY_A - (totalmass/clustervolume))/(celldensity-1);
602 else
603 cellvolume = (TotalNoClusters*totalmass/SOLVENTDENSITY_a0 - (totalmass/clustervolume))/(celldensity-1);
604 *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
605
606 double minimumvolume = TotalNoClusters*(GreatestDiameter[0]*GreatestDiameter[1]*GreatestDiameter[2]);
607 *out << Verbose(1) << "Minimum volume of the convex envelope contained in a rectangular box is " << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
608 if (minimumvolume > cellvolume) {
609 cerr << Verbose(0) << "ERROR: the containing box already has a greater volume than the envisaged cell volume!" << endl;
610 cout << Verbose(0) << "Setting Box dimensions to minimum possible, the greatest diameters." << endl;
611 for(int i=0;i<NDIM;i++)
612 BoxLengths.x[i] = GreatestDiameter[i];
613 mol->CenterEdge(out, &BoxLengths);
614 } else {
615 BoxLengths.x[0] = (repetition[0]*GreatestDiameter[0] + repetition[1]*GreatestDiameter[1] + repetition[2]*GreatestDiameter[2]);
616 BoxLengths.x[1] = (repetition[0]*repetition[1]*GreatestDiameter[0]*GreatestDiameter[1]
617 + repetition[0]*repetition[2]*GreatestDiameter[0]*GreatestDiameter[2]
618 + repetition[1]*repetition[2]*GreatestDiameter[1]*GreatestDiameter[2]);
619 BoxLengths.x[2] = minimumvolume - cellvolume;
620 double x0 = 0.,x1 = 0.,x2 = 0.;
621 if (gsl_poly_solve_cubic(BoxLengths.x[0],BoxLengths.x[1],BoxLengths.x[2],&x0,&x1,&x2) == 1) // either 1 or 3 on return
622 *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0 << " ." << endl;
623 else {
624 *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0 << " and " << x1 << " and " << x2 << " ." << endl;
625 x0 = x2; // sorted in ascending order
626 }
627
628 cellvolume = 1;
629 for(int i=0;i<NDIM;i++) {
630 BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]);
631 cellvolume *= BoxLengths.x[i];
632 }
633
634 // set new box dimensions
635 *out << Verbose(0) << "Translating to box with these boundaries." << endl;
636 mol->CenterInBox((ofstream *)&cout, &BoxLengths);
637 }
638 // update Box of atoms by boundary
639 mol->SetBoxDimension(&BoxLengths);
640 *out << Verbose(0) << "RESULT: The resulting cell dimensions are: " << BoxLengths.x[0] << " and " << BoxLengths.x[1] << " and " << BoxLengths.x[2] << " with total volume of " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
641};
642
643
644// =========================================================== class TESSELATION ===========================================
645
646/** Constructor of class Tesselation.
647 */
648Tesselation::Tesselation()
649{
650 PointsOnBoundaryCount = 0;
651 LinesOnBoundaryCount = 0;
652 TrianglesOnBoundaryCount = 0;
653};
654
655/** Constructor of class Tesselation.
656 * We have to free all points, lines and triangles.
657 */
658Tesselation::~Tesselation()
659{
660 for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner != TrianglesOnBoundary.end(); runner++) {
661 delete(runner->second);
662 }
663};
664
665/** Gueses first starting triangle of the convex envelope.
666 * We guess the starting triangle by taking the smallest distance between two points and looking for a fitting third.
667 * \param *out output stream for debugging
668 * \param PointsOnBoundary set of boundary points defining the convex envelope of the cluster
669 */
670void Tesselation::GuessStartingTriangle(ofstream *out)
671{
672 // 4b. create a starting triangle
673 // 4b1. create all distances
674 DistanceMultiMap DistanceMMap;
675 double distance, tmp;
676 Vector PlaneVector, TrialVector;
677 PointMap::iterator A, B, C; // three nodes of the first triangle
678 A = PointsOnBoundary.begin(); // the first may be chosen arbitrarily
679
680 // with A chosen, take each pair B,C and sort
681 if (A != PointsOnBoundary.end()) {
682 B = A;
683 B++;
684 for (; B != PointsOnBoundary.end(); B++) {
685 C = B;
686 C++;
687 for (; C != PointsOnBoundary.end(); C++) {
688 tmp = A->second->node->x.Distance(&B->second->node->x);
689 distance = tmp*tmp;
690 tmp = A->second->node->x.Distance(&C->second->node->x);
691 distance += tmp*tmp;
692 tmp = B->second->node->x.Distance(&C->second->node->x);
693 distance += tmp*tmp;
694 DistanceMMap.insert( DistanceMultiMapPair(distance, pair<PointMap::iterator, PointMap::iterator>(B,C) ) );
695 }
696 }
697 }
698// // listing distances
699// *out << Verbose(1) << "Listing DistanceMMap:";
700// for(DistanceMultiMap::iterator runner = DistanceMMap.begin(); runner != DistanceMMap.end(); runner++) {
701// *out << " " << runner->first << "(" << *runner->second.first->second << ", " << *runner->second.second->second << ")";
702// }
703// *out << endl;
704
705 // 4b2. pick three baselines forming a triangle
706 // 1. we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
707 DistanceMultiMap::iterator baseline = DistanceMMap.begin();
708 for (; baseline != DistanceMMap.end(); baseline++) {
709 // we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
710 // 2. next, we have to check whether all points reside on only one side of the triangle
711 // 3. construct plane vector
712 PlaneVector.MakeNormalVector(&A->second->node->x, &baseline->second.first->second->node->x, &baseline->second.second->second->node->x);
713 *out << Verbose(2) << "Plane vector of candidate triangle is ";
714 PlaneVector.Output(out);
715 *out << endl;
716 // 4. loop over all points
717 double sign = 0.;
718 PointMap::iterator checker = PointsOnBoundary.begin();
719 for (; checker != PointsOnBoundary.end(); checker++) {
720 // (neglecting A,B,C)
721 if ((checker == A) || (checker == baseline->second.first) || (checker == baseline->second.second))
722 continue;
723 // 4a. project onto plane vector
724 TrialVector.CopyVector(&checker->second->node->x);
725 TrialVector.SubtractVector(&A->second->node->x);
726 distance = TrialVector.Projection(&PlaneVector);
727 if (fabs(distance) < 1e-4) // we need to have a small epsilon around 0 which is still ok
728 continue;
729 *out << Verbose(3) << "Projection of " << checker->second->node->Name << " yields distance of " << distance << "." << endl;
730 tmp = distance/fabs(distance);
731 // 4b. Any have different sign to than before? (i.e. would lie outside convex hull with this starting triangle)
732 if ((sign != 0) && (tmp != sign)) {
733 // 4c. If so, break 4. loop and continue with next candidate in 1. loop
734 *out << Verbose(2) << "Current candidates: " << A->second->node->Name << "," << baseline->second.first->second->node->Name << "," << baseline->second.second->second->node->Name << " leave " << checker->second->node->Name << " outside the convex hull." << endl;
735 break;
736 } else { // note the sign for later
737 *out << Verbose(2) << "Current candidates: " << A->second->node->Name << "," << baseline->second.first->second->node->Name << "," << baseline->second.second->second->node->Name << " leave " << checker->second->node->Name << " inside the convex hull." << endl;
738 sign = tmp;
739 }
740 // 4d. Check whether the point is inside the triangle (check distance to each node
741 tmp = checker->second->node->x.Distance(&A->second->node->x);
742 int innerpoint = 0;
743 if ((tmp < A->second->node->x.Distance(&baseline->second.first->second->node->x))
744 && (tmp < A->second->node->x.Distance(&baseline->second.second->second->node->x)))
745 innerpoint++;
746 tmp = checker->second->node->x.Distance(&baseline->second.first->second->node->x);
747 if ((tmp < baseline->second.first->second->node->x.Distance(&A->second->node->x))
748 && (tmp < baseline->second.first->second->node->x.Distance(&baseline->second.second->second->node->x)))
749 innerpoint++;
750 tmp = checker->second->node->x.Distance(&baseline->second.second->second->node->x);
751 if ((tmp < baseline->second.second->second->node->x.Distance(&baseline->second.first->second->node->x))
752 && (tmp < baseline->second.second->second->node->x.Distance(&A->second->node->x)))
753 innerpoint++;
754 // 4e. If so, break 4. loop and continue with next candidate in 1. loop
755 if (innerpoint == 3)
756 break;
757 }
758 // 5. come this far, all on same side? Then break 1. loop and construct triangle
759 if (checker == PointsOnBoundary.end()) {
760 *out << "Looks like we have a candidate!" << endl;
761 break;
762 }
763 }
764 if (baseline != DistanceMMap.end()) {
765 BPS[0] = baseline->second.first->second;
766 BPS[1] = baseline->second.second->second;
767 BLS[0] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
768 BPS[0] = A->second;
769 BPS[1] = baseline->second.second->second;
770 BLS[1] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
771 BPS[0] = baseline->second.first->second;
772 BPS[1] = A->second;
773 BLS[2] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
774
775 // 4b3. insert created triangle
776 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
777 TrianglesOnBoundary.insert( TrianglePair(TrianglesOnBoundaryCount, BTS) );
778 TrianglesOnBoundaryCount++;
779 for(int i=0;i<NDIM;i++) {
780 LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BTS->lines[i]) );
781 LinesOnBoundaryCount++;
782 }
783
784 *out << Verbose(1) << "Starting triangle is " << *BTS << "." << endl;
785 } else {
786 *out << Verbose(1) << "No starting triangle found." << endl;
787 exit(255);
788 }
789};
790
791
792/** Tesselates the convex envelope of a cluster from a single starting triangle.
793 * The starting triangle is made out of three baselines. Each line in the final tesselated cluster may belong to at most
794 * 2 triangles. Hence, we go through all current lines:
795 * -# if the lines contains to only one triangle
796 * -# We search all points in the boundary
797 * -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors
798 * -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to
799 * baseline in triangle plane pointing out of the triangle and normal vector of new triangle)
800 * -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount)
801 * \param *out output stream for debugging
802 * \param *configuration for IsAngstroem
803 * \param *mol the cluster as a molecule structure
804 */
805void Tesselation::TesselateOnBoundary(ofstream *out, config *configuration, molecule *mol)
806{
807 bool flag;
808 PointMap::iterator winner;
809 class BoundaryPointSet *peak = NULL;
810 double SmallestAngle, TempAngle;
811 Vector NormalVector, VirtualNormalVector, CenterVector, TempVector, PropagationVector;
812 LineMap::iterator LineChecker[2];
813 do {
814 flag = false;
815 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline++)
816 if (baseline->second->TrianglesCount == 1) {
817 *out << Verbose(2) << "Current baseline is between " << *(baseline->second) << "." << endl;
818 // 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)
819 SmallestAngle = M_PI;
820 BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far
821 // get peak point with respect to this base line's only triangle
822 for(int i=0;i<3;i++)
823 if ((BTS->endpoints[i] != baseline->second->endpoints[0]) && (BTS->endpoints[i] != baseline->second->endpoints[1]))
824 peak = BTS->endpoints[i];
825 *out << Verbose(3) << " and has peak " << *peak << "." << endl;
826 // normal vector of triangle
827 BTS->GetNormalVector(NormalVector);
828 *out << Verbose(4) << "NormalVector of base triangle is ";
829 NormalVector.Output(out);
830 *out << endl;
831 // offset to center of triangle
832 CenterVector.Zero();
833 for(int i=0;i<3;i++)
834 CenterVector.AddVector(&BTS->endpoints[i]->node->x);
835 CenterVector.Scale(1./3.);
836 *out << Verbose(4) << "CenterVector of base triangle is ";
837 CenterVector.Output(out);
838 *out << endl;
839 // vector in propagation direction (out of triangle)
840 // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection)
841 TempVector.CopyVector(&baseline->second->endpoints[0]->node->x);
842 TempVector.SubtractVector(&baseline->second->endpoints[1]->node->x);
843 PropagationVector.MakeNormalVector(&TempVector, &NormalVector);
844 TempVector.CopyVector(&CenterVector);
845 TempVector.SubtractVector(&baseline->second->endpoints[0]->node->x); // TempVector is vector on triangle plane pointing from one baseline egde towards center!
846 //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl;
847 if (PropagationVector.Projection(&TempVector) > 0) // make sure normal propagation vector points outward from baseline
848 PropagationVector.Scale(-1.);
849 *out << Verbose(4) << "PropagationVector of base triangle is ";
850 PropagationVector.Output(out);
851 *out << endl;
852 winner = PointsOnBoundary.end();
853 for (PointMap::iterator target = PointsOnBoundary.begin(); target != PointsOnBoundary.end(); target++)
854 if ((target->second != baseline->second->endpoints[0]) && (target->second != baseline->second->endpoints[1])) { // don't take the same endpoints
855 *out << Verbose(3) << "Target point is " << *(target->second) << ":";
856 bool continueflag = true;
857
858 VirtualNormalVector.CopyVector(&baseline->second->endpoints[0]->node->x);
859 VirtualNormalVector.AddVector(&baseline->second->endpoints[0]->node->x);
860 VirtualNormalVector.Scale(-1./2.); // points now to center of base line
861 VirtualNormalVector.AddVector(&target->second->node->x); // points from center of base line to target
862 TempAngle = VirtualNormalVector.Angle(&PropagationVector);
863 continueflag = continueflag && (TempAngle < (M_PI/2.)); // no bends bigger than Pi/2 (90 degrees)
864 if (!continueflag) {
865 *out << Verbose(4) << "Angle between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", bad direction!" << endl;
866 continue;
867 } else
868 *out << Verbose(4) << "Angle between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", good direction!" << endl;
869 LineChecker[0] = baseline->second->endpoints[0]->lines.find(target->first);
870 LineChecker[1] = baseline->second->endpoints[1]->lines.find(target->first);
871 // if (LineChecker[0] != baseline->second->endpoints[0]->lines.end())
872 // *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl;
873 // else
874 // *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has no line to " << *(target->second) << " as endpoint." << endl;
875 // if (LineChecker[1] != baseline->second->endpoints[1]->lines.end())
876 // *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl;
877 // else
878 // *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has no line to " << *(target->second) << " as endpoint." << endl;
879 // check first endpoint (if any connecting line goes to target or at least not more than 1)
880 continueflag = continueflag && (( (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) || (LineChecker[0]->second->TrianglesCount == 1)));
881 if (!continueflag) {
882 *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl;
883 continue;
884 }
885 // check second endpoint (if any connecting line goes to target or at least not more than 1)
886 continueflag = continueflag && (( (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) || (LineChecker[1]->second->TrianglesCount == 1)));
887 if (!continueflag) {
888 *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl;
889 continue;
890 }
891 // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint)
892 continueflag = continueflag && (!(
893 ((LineChecker[0] != baseline->second->endpoints[0]->lines.end()) && (LineChecker[1] != baseline->second->endpoints[1]->lines.end())
894 && (GetCommonEndpoint(LineChecker[0]->second, LineChecker[1]->second) == peak))
895 ));
896 if (!continueflag) {
897 *out << Verbose(4) << "Current target is peak!" << endl;
898 continue;
899 }
900 // in case NOT both were found
901 if (continueflag) { // create virtually this triangle, get its normal vector, calculate angle
902 flag = true;
903 VirtualNormalVector.MakeNormalVector(&baseline->second->endpoints[0]->node->x, &baseline->second->endpoints[1]->node->x, &target->second->node->x);
904 // make it always point inward
905 if (baseline->second->endpoints[0]->node->x.Projection(&VirtualNormalVector) > 0)
906 VirtualNormalVector.Scale(-1.);
907 // calculate angle
908 TempAngle = NormalVector.Angle(&VirtualNormalVector);
909 *out << Verbose(4) << "NormalVector is ";
910 VirtualNormalVector.Output(out);
911 *out << " and the angle is " << TempAngle << "." << endl;
912 if (SmallestAngle > TempAngle) { // set to new possible winner
913 SmallestAngle = TempAngle;
914 winner = target;
915 }
916 }
917 }
918 // 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
919 if (winner != PointsOnBoundary.end()) {
920 *out << Verbose(2) << "Winning target point is " << *(winner->second) << " with angle " << SmallestAngle << "." << endl;
921 // create the lins of not yet present
922 BLS[0] = baseline->second;
923 // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles)
924 LineChecker[0] = baseline->second->endpoints[0]->lines.find(winner->first);
925 LineChecker[1] = baseline->second->endpoints[1]->lines.find(winner->first);
926 if (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) { // create
927 BPS[0] = baseline->second->endpoints[0];
928 BPS[1] = winner->second;
929 BLS[1] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
930 LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BLS[1]) );
931 LinesOnBoundaryCount++;
932 } else
933 BLS[1] = LineChecker[0]->second;
934 if (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) { // create
935 BPS[0] = baseline->second->endpoints[1];
936 BPS[1] = winner->second;
937 BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
938 LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BLS[2]) );
939 LinesOnBoundaryCount++;
940 } else
941 BLS[2] = LineChecker[1]->second;
942 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
943 TrianglesOnBoundary.insert( TrianglePair(TrianglesOnBoundaryCount, BTS) );
944 TrianglesOnBoundaryCount++;
945 } else {
946 *out << Verbose(1) << "I could not determine a winner for this baseline " << *(baseline->second) << "." << endl;
947 }
948
949 // 5d. If the set of lines is not yet empty, go to 5. and continue
950 } else
951 *out << Verbose(2) << "Baseline candidate " << *(baseline->second) << " has a triangle count of " << baseline->second->TrianglesCount << "." << endl;
952 } while (flag);
953
954 stringstream line;
955 line << configuration->configpath << "/" << CONVEXENVELOPE;
956 *out << Verbose(1) << "Storing convex envelope in tecplot data file " << line.str() << "." << endl;
957 ofstream output(line.str().c_str());
958 output << "TITLE = \"3D CONVEX SHELL\"" << endl;
959 output << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl;
960 output << "ZONE T=\"TRIANGLES\", N=" << PointsOnBoundaryCount << ", E=" << TrianglesOnBoundaryCount << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl;
961 int *LookupList = new int[mol->AtomCount];
962 for (int i=0;i<mol->AtomCount;i++)
963 LookupList[i] = -1;
964
965 // print atom coordinates
966 *out << Verbose(2) << "The following triangles were created:";
967 int Counter = 1;
968 atom *Walker = NULL;
969 for (PointMap::iterator target = PointsOnBoundary.begin(); target != PointsOnBoundary.end(); target++) {
970 Walker = target->second->node;
971 LookupList[Walker->nr] = Counter++;
972 output << Walker->x.x[0] << " " << Walker->x.x[1] << " " << Walker->x.x[2] << " " << endl;
973 }
974 output << endl;
975 // print connectivity
976 for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner != TrianglesOnBoundary.end(); runner++) {
977 *out << " " << runner->second->endpoints[0]->node->Name << "<->" << runner->second->endpoints[1]->node->Name << "<->" << runner->second->endpoints[2]->node->Name;
978 output << LookupList[runner->second->endpoints[0]->node->nr] << " " << LookupList[runner->second->endpoints[1]->node->nr] << " " << LookupList[runner->second->endpoints[2]->node->nr] << endl;
979 }
980 output.close();
981 delete[](LookupList);
982 *out << endl;
983};
984
985/** Adds an atom to the tesselation::PointsOnBoundary list.
986 * \param *Walker atom to add
987 */
988void Tesselation::AddPoint(atom *Walker)
989{
990 PointTestPair InsertUnique;
991 BPS[0] = new class BoundaryPointSet(Walker);
992 InsertUnique = PointsOnBoundary.insert( PointPair(Walker->nr, BPS[0]) );
993 if (InsertUnique.second) // if new point was not present before, increase counter
994 PointsOnBoundaryCount++;
995};
Note: See TracBrowser for help on using the repository browser.