source: src/boundary.cpp@ 03648b

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 03648b was 03648b, checked in by Christian Neuen <neuen@…>, 16 years ago

In vector a function for calculation of the vector-(cross-)product has been added.
In Boundary a new way for finding the non-convex boundary is implemented.
Currently problem with comparison of the return value of the map::find routine.

  • Property mode set to 100644
File size: 58.1 KB
Line 
1#include "molecules.hpp"
2#include "boundary.hpp"
3
4
5// =================spaeter gebrauchte
6void Find_next_suitable_point(atom a, atom b, atom Candidate, int n, Vector *d1, Vector *d2, double *Storage, const double RADIUS, molecule mol);
7void Find_non_convex_border(Tesselation Tess, molecule mol);
8
9
10// ======================================== Points on Boundary =================================
11
12BoundaryPointSet::BoundaryPointSet()
13{
14 LinesCount = 0;
15 Nr = -1;
16};
17
18BoundaryPointSet::BoundaryPointSet(atom *Walker)
19{
20 node = Walker;
21 LinesCount = 0;
22 Nr = Walker->nr;
23};
24
25BoundaryPointSet::~BoundaryPointSet()
26{
27 cout << Verbose(5) << "Erasing point nr. " << Nr << "." << endl;
28 node = NULL;
29};
30
31void BoundaryPointSet::AddLine(class BoundaryLineSet *line)
32{
33 cout << Verbose(6) << "Adding line " << *line << " to " << *this << "." << endl;
34 if (line->endpoints[0] == this) {
35 lines.insert ( LinePair( line->endpoints[1]->Nr, line) );
36 } else {
37 lines.insert ( LinePair( line->endpoints[0]->Nr, line) );
38 }
39 LinesCount++;
40};
41
42ostream & operator << (ostream &ost, BoundaryPointSet &a)
43{
44 ost << "[" << a.Nr << "|" << a.node->Name << "]";
45 return ost;
46};
47
48// ======================================== Lines on Boundary =================================
49
50BoundaryLineSet::BoundaryLineSet()
51{
52 for (int i=0;i<2;i++)
53 endpoints[i] = NULL;
54 TrianglesCount = 0;
55 Nr = -1;
56};
57
58BoundaryLineSet::BoundaryLineSet(class BoundaryPointSet *Point[2], int number)
59{
60 // set number
61 Nr = number;
62 // set endpoints in ascending order
63 SetEndpointsOrdered(endpoints, Point[0], Point[1]);
64 // add this line to the hash maps of both endpoints
65 Point[0]->AddLine(this);
66 Point[1]->AddLine(this);
67 // clear triangles list
68 TrianglesCount = 0;
69 cout << Verbose(5) << "New Line with endpoints " << *this << "." << endl;
70};
71
72BoundaryLineSet::~BoundaryLineSet()
73{
74 for (int i=0;i<2;i++) {
75 cout << Verbose(5) << "Erasing Line Nr. " << Nr << " in boundary point " << *endpoints[i] << "." << endl;
76 endpoints[i]->lines.erase(Nr);
77 LineMap::iterator tester = endpoints[i]->lines.begin();
78 tester++;
79 if (tester == endpoints[i]->lines.end()) {
80 cout << Verbose(5) << *endpoints[i] << " has no more lines it's attached to, erasing." << endl;
81 delete(endpoints[i]);
82 } else
83 cout << Verbose(5) << *endpoints[i] << " has still lines it's attached to." << endl;
84 }
85};
86
87void BoundaryLineSet::AddTriangle(class BoundaryTriangleSet *triangle)
88{
89 cout << Verbose(6) << "Add " << triangle->Nr << " to line " << *this << "." << endl;
90 triangles.insert ( TrianglePair( TrianglesCount, triangle) );
91 TrianglesCount++;
92};
93
94ostream & operator << (ostream &ost, BoundaryLineSet &a)
95{
96 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << "," << a.endpoints[1]->node->Name << "]";
97 return ost;
98};
99
100// ======================================== Triangles on Boundary =================================
101
102
103BoundaryTriangleSet::BoundaryTriangleSet()
104{
105 for (int i=0;i<3;i++) {
106 endpoints[i] = NULL;
107 lines[i] = NULL;
108 }
109 Nr = -1;
110};
111
112BoundaryTriangleSet::BoundaryTriangleSet(class BoundaryLineSet *line[3], int number)
113{
114 // set number
115 Nr = number;
116 // set lines
117 cout << Verbose(5) << "New triangle " << Nr << ":" << endl;
118 for (int i=0;i<3;i++) {
119 lines[i] = line[i];
120 lines[i]->AddTriangle(this);
121 }
122 // get ascending order of endpoints
123 map <int, class BoundaryPointSet * > OrderMap;
124 for(int i=0;i<3;i++) // for all three lines
125 for (int j=0;j<2;j++) { // for both endpoints
126 OrderMap.insert ( pair <int, class BoundaryPointSet * >( line[i]->endpoints[j]->Nr, line[i]->endpoints[j]) );
127 // and we don't care whether insertion fails
128 }
129 // set endpoints
130 int Counter = 0;
131 cout << Verbose(6) << " with end points ";
132 for (map <int, class BoundaryPointSet * >::iterator runner = OrderMap.begin(); runner != OrderMap.end(); runner++) {
133 endpoints[Counter] = runner->second;
134 cout << " " << *endpoints[Counter];
135 Counter++;
136 }
137 if (Counter < 3) {
138 cerr << "ERROR! We have a triangle with only two distinct endpoints!" << endl;
139 //exit(1);
140 }
141 cout << "." << endl;
142};
143
144BoundaryTriangleSet::~BoundaryTriangleSet()
145{
146 for (int i=0;i<3;i++) {
147 cout << Verbose(5) << "Erasing triangle Nr." << Nr << endl;
148 lines[i]->triangles.erase(Nr);
149 TriangleMap::iterator tester = lines[i]->triangles.begin();
150 tester++;
151 if (tester == lines[i]->triangles.end()) {
152 cout << Verbose(5) << *lines[i] << " is no more attached to any triangle, erasing." << endl;
153 delete(lines[i]);
154 } else
155 cout << Verbose(5) << *lines[i] << " is still attached to a triangle." << endl;
156 }
157};
158
159void BoundaryTriangleSet::GetNormalVector(Vector &NormalVector)
160{
161 // get normal vector
162 NormalVector.MakeNormalVector(&endpoints[0]->node->x, &endpoints[1]->node->x, &endpoints[2]->node->x);
163
164 // make it always point inward (any offset vector onto plane projected onto normal vector suffices)
165 if (endpoints[0]->node->x.Projection(&NormalVector) > 0)
166 NormalVector.Scale(-1.);
167};
168
169ostream & operator << (ostream &ost, BoundaryTriangleSet &a)
170{
171 ost << "[" << a.Nr << "|" << a.endpoints[0]->node->Name << "," << a.endpoints[1]->node->Name << "," << a.endpoints[2]->node->Name << "]";
172 return ost;
173};
174
175// ========================================== F U N C T I O N S =================================
176
177/** Finds the endpoint two lines are sharing.
178 * \param *line1 first line
179 * \param *line2 second line
180 * \return point which is shared or NULL if none
181 */
182class BoundaryPointSet * GetCommonEndpoint(class BoundaryLineSet * line1, class BoundaryLineSet * line2)
183{
184 class BoundaryLineSet * lines[2] = {line1, line2};
185 class BoundaryPointSet *node = NULL;
186 map <int, class BoundaryPointSet * > OrderMap;
187 pair < map <int, class BoundaryPointSet * >::iterator, bool > OrderTest;
188 for(int i=0;i<2;i++) // for both lines
189 for (int j=0;j<2;j++) { // for both endpoints
190 OrderTest = OrderMap.insert ( pair <int, class BoundaryPointSet * >( lines[i]->endpoints[j]->Nr, lines[i]->endpoints[j]) );
191 if (!OrderTest.second) { // if insertion fails, we have common endpoint
192 node = OrderTest.first->second;
193 cout << Verbose(5) << "Common endpoint of lines " << *line1 << " and " << *line2 << " is: " << *node << "." << endl;
194 j=2;
195 i=2;
196 break;
197 }
198 }
199 return node;
200};
201
202/** Determines the boundary points of a cluster.
203 * Does a projection per axis onto the orthogonal plane, transforms into spherical coordinates, sorts them by the angle
204 * and looks at triples: if the middle has less a distance than the allowed maximum height of the triangle formed by the plane's
205 * center and first and last point in the triple, it is thrown out.
206 * \param *out output stream for debugging
207 * \param *mol molecule structure representing the cluster
208 */
209Boundaries * GetBoundaryPoints(ofstream *out, molecule *mol)
210{
211 atom *Walker = NULL;
212 PointMap PointsOnBoundary;
213 LineMap LinesOnBoundary;
214 TriangleMap TrianglesOnBoundary;
215
216 *out << Verbose(1) << "Finding all boundary points." << endl;
217 Boundaries *BoundaryPoints = new Boundaries [NDIM]; // first is alpha, second is (r, nr)
218 BoundariesTestPair BoundaryTestPair;
219 Vector AxisVector, AngleReferenceVector, AngleReferenceNormalVector;
220 double radius, angle;
221 // 3a. Go through every axis
222 for (int axis=0; axis<NDIM; axis++) {
223 AxisVector.Zero();
224 AngleReferenceVector.Zero();
225 AngleReferenceNormalVector.Zero();
226 AxisVector.x[axis] = 1.;
227 AngleReferenceVector.x[(axis+1)%NDIM] = 1.;
228 AngleReferenceNormalVector.x[(axis+2)%NDIM] = 1.;
229 // *out << Verbose(1) << "Axisvector is ";
230 // AxisVector.Output(out);
231 // *out << " and AngleReferenceVector is ";
232 // AngleReferenceVector.Output(out);
233 // *out << "." << endl;
234 // *out << " and AngleReferenceNormalVector is ";
235 // AngleReferenceNormalVector.Output(out);
236 // *out << "." << endl;
237 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
238 Walker = mol->start;
239 while (Walker->next != mol->end) {
240 Walker = Walker->next;
241 Vector ProjectedVector;
242 ProjectedVector.CopyVector(&Walker->x);
243 ProjectedVector.ProjectOntoPlane(&AxisVector);
244 // correct for negative side
245 //if (Projection(y) < 0)
246 //angle = 2.*M_PI - angle;
247 radius = ProjectedVector.Norm();
248 if (fabs(radius) > MYEPSILON)
249 angle = ProjectedVector.Angle(&AngleReferenceVector);
250 else
251 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
252
253 //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl;
254 if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0) {
255 angle = 2.*M_PI - angle;
256 }
257 //*out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): ";
258 //ProjectedVector.Output(out);
259 //*out << endl;
260 BoundaryTestPair = BoundaryPoints[axis].insert( BoundariesPair (angle, DistancePair (radius, Walker) ) );
261 if (BoundaryTestPair.second) { // successfully inserted
262 } else { // same point exists, check first r, then distance of original vectors to center of gravity
263 *out << Verbose(2) << "Encountered two vectors whose projection onto axis " << axis << " is equal: " << endl;
264 *out << Verbose(2) << "Present vector: ";
265 BoundaryTestPair.first->second.second->x.Output(out);
266 *out << endl;
267 *out << Verbose(2) << "New vector: ";
268 Walker->x.Output(out);
269 *out << endl;
270 double tmp = ProjectedVector.Norm();
271 if (tmp > BoundaryTestPair.first->second.first) {
272 BoundaryTestPair.first->second.first = tmp;
273 BoundaryTestPair.first->second.second = Walker;
274 *out << Verbose(2) << "Keeping new vector." << endl;
275 } else if (tmp == BoundaryTestPair.first->second.first) {
276 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
277 BoundaryTestPair.first->second.second = Walker;
278 *out << Verbose(2) << "Keeping new vector." << endl;
279 } else {
280 *out << Verbose(2) << "Keeping present vector." << endl;
281 }
282 } else {
283 *out << Verbose(2) << "Keeping present vector." << endl;
284 }
285 }
286 }
287 // printing all inserted for debugging
288 // {
289 // *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
290 // int i=0;
291 // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
292 // if (runner != BoundaryPoints[axis].begin())
293 // *out << ", " << i << ": " << *runner->second.second;
294 // else
295 // *out << i << ": " << *runner->second.second;
296 // i++;
297 // }
298 // *out << endl;
299 // }
300 // 3c. throw out points whose distance is less than the mean of left and right neighbours
301 bool flag = false;
302 do { // do as long as we still throw one out per round
303 *out << Verbose(1) << "Looking for candidates to kick out by convex condition ... " << endl;
304 flag = false;
305 Boundaries::iterator left = BoundaryPoints[axis].end();
306 Boundaries::iterator right = BoundaryPoints[axis].end();
307 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
308 // set neighbours correctly
309 if (runner == BoundaryPoints[axis].begin()) {
310 left = BoundaryPoints[axis].end();
311 } else {
312 left = runner;
313 }
314 left--;
315 right = runner;
316 right++;
317 if (right == BoundaryPoints[axis].end()) {
318 right = BoundaryPoints[axis].begin();
319 }
320 // check distance
321
322 // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)
323 {
324 Vector SideA, SideB, SideC, SideH;
325 SideA.CopyVector(&left->second.second->x);
326 SideA.ProjectOntoPlane(&AxisVector);
327 // *out << "SideA: ";
328 // SideA.Output(out);
329 // *out << endl;
330
331 SideB.CopyVector(&right->second.second->x);
332 SideB.ProjectOntoPlane(&AxisVector);
333 // *out << "SideB: ";
334 // SideB.Output(out);
335 // *out << endl;
336
337 SideC.CopyVector(&left->second.second->x);
338 SideC.SubtractVector(&right->second.second->x);
339 SideC.ProjectOntoPlane(&AxisVector);
340 // *out << "SideC: ";
341 // SideC.Output(out);
342 // *out << endl;
343
344 SideH.CopyVector(&runner->second.second->x);
345 SideH.ProjectOntoPlane(&AxisVector);
346 // *out << "SideH: ";
347 // SideH.Output(out);
348 // *out << endl;
349
350 // calculate each length
351 double a = SideA.Norm();
352 //double b = SideB.Norm();
353 //double c = SideC.Norm();
354 double h = SideH.Norm();
355 // calculate the angles
356 double alpha = SideA.Angle(&SideH);
357 double beta = SideA.Angle(&SideC);
358 double gamma = SideB.Angle(&SideH);
359 double delta = SideC.Angle(&SideH);
360 double MinDistance = a * sin(beta)/(sin(delta)) * (((alpha < M_PI/2.) || (gamma < M_PI/2.)) ? 1. : -1.);
361 // *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;
362 //*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;
363 if ((fabs(h/fabs(h) - MinDistance/fabs(MinDistance)) < MYEPSILON) && (h < MinDistance)) {
364 // throw out point
365 //*out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl;
366 BoundaryPoints[axis].erase(runner);
367 flag = true;
368 }
369 }
370 }
371 } while (flag);
372 }
373 return BoundaryPoints;
374};
375
376/** Determines greatest diameters of a cluster defined by its convex envelope.
377 * Looks at lines parallel to one axis and where they intersect on the projected planes
378 * \param *out output stream for debugging
379 * \param *BoundaryPoints NDIM set of boundary points defining the convex envelope on each projected plane
380 * \param *mol molecule structure representing the cluster
381 * \param IsAngstroem whether we have angstroem or atomic units
382 * \return NDIM array of the diameters
383 */
384double * GetDiametersOfCluster(ofstream *out, Boundaries *BoundaryPtr, molecule *mol, bool IsAngstroem)
385{
386 // get points on boundary of NULL was given as parameter
387 bool BoundaryFreeFlag = false;
388 Boundaries *BoundaryPoints = BoundaryPtr;
389 if (BoundaryPoints == NULL) {
390 BoundaryFreeFlag = true;
391 BoundaryPoints = GetBoundaryPoints(out, mol);
392 } else {
393 *out << Verbose(1) << "Using given boundary points set." << endl;
394 }
395
396 // determine biggest "diameter" of cluster for each axis
397 Boundaries::iterator Neighbour, OtherNeighbour;
398 double *GreatestDiameter = new double[NDIM];
399 for(int i=0;i<NDIM;i++)
400 GreatestDiameter[i] = 0.;
401 double OldComponent, tmp, w1, w2;
402 Vector DistanceVector, OtherVector;
403 int component, Othercomponent;
404 for(int axis=0;axis<NDIM;axis++) { // regard each projected plane
405 //*out << Verbose(1) << "Current axis is " << axis << "." << endl;
406 for (int j=0;j<2;j++) { // and for both axis on the current plane
407 component = (axis+j+1)%NDIM;
408 Othercomponent = (axis+1+((j+1) & 1))%NDIM;
409 //*out << Verbose(1) << "Current component is " << component << ", Othercomponent is " << Othercomponent << "." << endl;
410 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
411 //*out << Verbose(2) << "Current runner is " << *(runner->second.second) << "." << endl;
412 // seek for the neighbours pair where the Othercomponent sign flips
413 Neighbour = runner;
414 Neighbour++;
415 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
416 Neighbour = BoundaryPoints[axis].begin();
417 DistanceVector.CopyVector(&runner->second.second->x);
418 DistanceVector.SubtractVector(&Neighbour->second.second->x);
419 do { // seek for neighbour pair where it flips
420 OldComponent = DistanceVector.x[Othercomponent];
421 Neighbour++;
422 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
423 Neighbour = BoundaryPoints[axis].begin();
424 DistanceVector.CopyVector(&runner->second.second->x);
425 DistanceVector.SubtractVector(&Neighbour->second.second->x);
426 //*out << Verbose(3) << "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << "." << endl;
427 } while ((runner != Neighbour) && ( fabs( OldComponent/fabs(OldComponent) - DistanceVector.x[Othercomponent]/fabs(DistanceVector.x[Othercomponent]) ) < MYEPSILON)); // as long as sign does not flip
428 if (runner != Neighbour) {
429 OtherNeighbour = Neighbour;
430 if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around
431 OtherNeighbour = BoundaryPoints[axis].end();
432 OtherNeighbour--;
433 //*out << Verbose(2) << "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << "." << endl;
434 // now we have found the pair: Neighbour and OtherNeighbour
435 OtherVector.CopyVector(&runner->second.second->x);
436 OtherVector.SubtractVector(&OtherNeighbour->second.second->x);
437 //*out << Verbose(2) << "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << "." << endl;
438 //*out << Verbose(2) << "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << "." << endl;
439 // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour
440 w1 = fabs(OtherVector.x[Othercomponent]);
441 w2 = fabs(DistanceVector.x[Othercomponent]);
442 tmp = fabs((w1*DistanceVector.x[component] + w2*OtherVector.x[component])/(w1+w2));
443 // mark if it has greater diameter
444 //*out << Verbose(2) << "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << "." << endl;
445 GreatestDiameter[component] = (GreatestDiameter[component] > tmp) ? GreatestDiameter[component] : tmp;
446 } //else
447 //*out << Verbose(2) << "Saw no sign flip, probably top or bottom node." << endl;
448 }
449 }
450 }
451 *out << Verbose(0) << "RESULT: The biggest diameters are " << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and " << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "." << endl;
452
453 // free reference lists
454 if (BoundaryFreeFlag)
455 delete[](BoundaryPoints);
456
457 return GreatestDiameter;
458};
459
460
461/** Determines the volume of a cluster.
462 * Determines first the convex envelope, then tesselates it and calculates its volume.
463 * \param *out output stream for debugging
464 * \param *tecplot output stream for tecplot data
465 * \param *configuration needed for path to store convex envelope file
466 * \param *BoundaryPoints NDIM set of boundary points on the projected plane per axis, on return if desired
467 * \param *mol molecule structure representing the cluster
468 * \return determined volume of the cluster in cubed config:GetIsAngstroem()
469 */
470double VolumeOfConvexEnvelope(ofstream *out, ofstream *tecplot, config *configuration, Boundaries *BoundaryPtr, molecule *mol)
471{
472 bool IsAngstroem = configuration->GetIsAngstroem();
473 atom *Walker = NULL;
474 struct Tesselation *TesselStruct = new Tesselation;
475 bool BoundaryFreeFlag = false;
476 Boundaries *BoundaryPoints = BoundaryPtr;
477 double volume = 0.;
478 double PyramidVolume = 0.;
479 double G,h;
480 Vector x,y;
481 double a,b,c;
482
483 Find_non_convex_border(*TesselStruct, *mol);
484 /*
485 // 1. calculate center of gravity
486 *out << endl;
487 Vector *CenterOfGravity = mol->DetermineCenterOfGravity(out);
488
489 // 2. translate all points into CoG
490 *out << Verbose(1) << "Translating system to Center of Gravity." << endl;
491 Walker = mol->start;
492 while (Walker->next != mol->end) {
493 Walker = Walker->next;
494 Walker->x.Translate(CenterOfGravity);
495 }
496
497 // 3. Find all points on the boundary
498 if (BoundaryPoints == NULL) {
499 BoundaryFreeFlag = true;
500 BoundaryPoints = GetBoundaryPoints(out, mol);
501 } else {
502 *out << Verbose(1) << "Using given boundary points set." << endl;
503 }
504
505 // 4. fill the boundary point list
506 for (int axis=0;axis<NDIM;axis++)
507 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
508 TesselStruct->AddPoint(runner->second.second);
509 }
510
511 *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl;
512 // now we have the whole set of edge points in the BoundaryList
513
514 // listing for debugging
515// *out << Verbose(1) << "Listing PointsOnBoundary:";
516// for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
517// *out << " " << *runner->second;
518// }
519// *out << endl;
520
521 // 5a. guess starting triangle
522 TesselStruct->GuessStartingTriangle(out);
523
524 // 5b. go through all lines, that are not yet part of two triangles (only of one so far)
525 TesselStruct->TesselateOnBoundary(out, configuration, mol);
526
527 *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundaryCount << " triangles with " << TesselStruct->LinesOnBoundaryCount << " lines and " << TesselStruct->PointsOnBoundaryCount << " points." << endl;
528 */
529
530
531 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
532 *out << Verbose(1) << "Calculating the volume of the pyramids formed out of triangles and center of gravity." << endl;
533 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
534 x.CopyVector(&runner->second->endpoints[0]->node->x);
535 x.SubtractVector(&runner->second->endpoints[1]->node->x);
536 y.CopyVector(&runner->second->endpoints[0]->node->x);
537 y.SubtractVector(&runner->second->endpoints[2]->node->x);
538 a = sqrt(runner->second->endpoints[0]->node->x.Distance(&runner->second->endpoints[1]->node->x));
539 b = sqrt(runner->second->endpoints[0]->node->x.Distance(&runner->second->endpoints[2]->node->x));
540 c = sqrt(runner->second->endpoints[2]->node->x.Distance(&runner->second->endpoints[1]->node->x));
541 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
542 x.MakeNormalVector(&runner->second->endpoints[0]->node->x, &runner->second->endpoints[1]->node->x, &runner->second->endpoints[2]->node->x);
543 x.Scale(runner->second->endpoints[1]->node->x.Projection(&x));
544 h = x.Norm(); // distance of CoG to triangle
545 PyramidVolume = (1./3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
546 *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;
547 volume += PyramidVolume;
548 }
549 *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10) << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
550
551 /*
552 // 7. translate all points back from CoG
553 *out << Verbose(1) << "Translating system back from Center of Gravity." << endl;
554 CenterOfGravity->Scale(-1);
555 Walker = mol->start;
556 while (Walker->next != mol->end) {
557 Walker = Walker->next;
558 Walker->x.Translate(CenterOfGravity);
559 }
560 */
561
562
563
564
565
566 // 8. Store triangles in tecplot file
567 if (tecplot != NULL) {
568 *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl;
569 *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl;
570 *tecplot << "ZONE T=\"TRIANGLES\", N=" << TesselStruct->PointsOnBoundaryCount << ", E=" << TesselStruct->TrianglesOnBoundaryCount << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl;
571 int *LookupList = new int[mol->AtomCount];
572 for (int i=0;i<mol->AtomCount;i++)
573 LookupList[i] = -1;
574
575 // print atom coordinates
576 *out << Verbose(2) << "The following triangles were created:";
577 int Counter = 1;
578 atom *Walker = NULL;
579 for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target != TesselStruct->PointsOnBoundary.end(); target++) {
580 Walker = target->second->node;
581 LookupList[Walker->nr] = Counter++;
582 *tecplot << Walker->x.x[0] << " " << Walker->x.x[1] << " " << Walker->x.x[2] << " " << endl;
583 }
584 *tecplot << endl;
585 // print connectivity
586 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++) {
587 *out << " " << runner->second->endpoints[0]->node->Name << "<->" << runner->second->endpoints[1]->node->Name << "<->" << runner->second->endpoints[2]->node->Name;
588 *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " " << LookupList[runner->second->endpoints[1]->node->nr] << " " << LookupList[runner->second->endpoints[2]->node->nr] << endl;
589 }
590 delete[](LookupList);
591 *out << endl;
592 }
593
594 // free reference lists
595 if (BoundaryFreeFlag)
596 delete[](BoundaryPoints);
597
598 return volume;
599};
600
601
602/** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
603 * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
604 * \param *out output stream for debugging
605 * \param *configuration needed for path to store convex envelope file
606 * \param *mol molecule structure representing the cluster
607 * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead.
608 * \param celldensity desired average density in final cell
609 */
610void PrepareClustersinWater(ofstream *out, config *configuration, molecule *mol, double ClusterVolume, double celldensity)
611{
612 // transform to PAS
613 mol->PrincipalAxisSystem(out, true);
614
615 // some preparations beforehand
616 bool IsAngstroem = configuration->GetIsAngstroem();
617 Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol);
618 double clustervolume;
619 if (ClusterVolume == 0)
620 clustervolume = VolumeOfConvexEnvelope(out, NULL, configuration, BoundaryPoints, mol);
621 else
622 clustervolume = ClusterVolume;
623 double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, IsAngstroem);
624 Vector BoxLengths;
625 int repetition[NDIM] = {1, 1, 1};
626 int TotalNoClusters = 1;
627 for (int i=0;i<NDIM;i++)
628 TotalNoClusters *= repetition[i];
629
630 // sum up the atomic masses
631 double totalmass = 0.;
632 atom *Walker = mol->start;
633 while (Walker->next != mol->end) {
634 Walker = Walker->next;
635 totalmass += Walker->type->mass;
636 }
637 *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10) << totalmass << " atomicmassunit." << endl;
638
639 *out << Verbose(0) << "RESULT: The average density is " << setprecision(10) << totalmass/clustervolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
640
641 // solve cubic polynomial
642 *out << Verbose(1) << "Solving equidistant suspension in water problem ..." << endl;
643 double cellvolume;
644 if (IsAngstroem)
645 cellvolume = (TotalNoClusters*totalmass/SOLVENTDENSITY_A - (totalmass/clustervolume))/(celldensity-1);
646 else
647 cellvolume = (TotalNoClusters*totalmass/SOLVENTDENSITY_a0 - (totalmass/clustervolume))/(celldensity-1);
648 *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
649
650 double minimumvolume = TotalNoClusters*(GreatestDiameter[0]*GreatestDiameter[1]*GreatestDiameter[2]);
651 *out << Verbose(1) << "Minimum volume of the convex envelope contained in a rectangular box is " << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
652 if (minimumvolume > cellvolume) {
653 cerr << Verbose(0) << "ERROR: the containing box already has a greater volume than the envisaged cell volume!" << endl;
654 cout << Verbose(0) << "Setting Box dimensions to minimum possible, the greatest diameters." << endl;
655 for(int i=0;i<NDIM;i++)
656 BoxLengths.x[i] = GreatestDiameter[i];
657 mol->CenterEdge(out, &BoxLengths);
658 } else {
659 BoxLengths.x[0] = (repetition[0]*GreatestDiameter[0] + repetition[1]*GreatestDiameter[1] + repetition[2]*GreatestDiameter[2]);
660 BoxLengths.x[1] = (repetition[0]*repetition[1]*GreatestDiameter[0]*GreatestDiameter[1]
661 + repetition[0]*repetition[2]*GreatestDiameter[0]*GreatestDiameter[2]
662 + repetition[1]*repetition[2]*GreatestDiameter[1]*GreatestDiameter[2]);
663 BoxLengths.x[2] = minimumvolume - cellvolume;
664 double x0 = 0.,x1 = 0.,x2 = 0.;
665 if (gsl_poly_solve_cubic(BoxLengths.x[0],BoxLengths.x[1],BoxLengths.x[2],&x0,&x1,&x2) == 1) // either 1 or 3 on return
666 *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0 << " ." << endl;
667 else {
668 *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0 << " and " << x1 << " and " << x2 << " ." << endl;
669 x0 = x2; // sorted in ascending order
670 }
671
672 cellvolume = 1;
673 for(int i=0;i<NDIM;i++) {
674 BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]);
675 cellvolume *= BoxLengths.x[i];
676 }
677
678 // set new box dimensions
679 *out << Verbose(0) << "Translating to box with these boundaries." << endl;
680 mol->CenterInBox((ofstream *)&cout, &BoxLengths);
681 }
682 // update Box of atoms by boundary
683 mol->SetBoxDimension(&BoxLengths);
684 *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;
685};
686
687
688// =========================================================== class TESSELATION ===========================================
689
690/** Constructor of class Tesselation.
691 */
692Tesselation::Tesselation()
693{
694 PointsOnBoundaryCount = 0;
695 LinesOnBoundaryCount = 0;
696 TrianglesOnBoundaryCount = 0;
697};
698
699/** Constructor of class Tesselation.
700 * We have to free all points, lines and triangles.
701 */
702Tesselation::~Tesselation()
703{
704 for (TriangleMap::iterator runner = TrianglesOnBoundary.begin(); runner != TrianglesOnBoundary.end(); runner++) {
705 delete(runner->second);
706 }
707};
708
709/** Gueses first starting triangle of the convex envelope.
710 * We guess the starting triangle by taking the smallest distance between two points and looking for a fitting third.
711 * \param *out output stream for debugging
712 * \param PointsOnBoundary set of boundary points defining the convex envelope of the cluster
713 */
714void Tesselation::GuessStartingTriangle(ofstream *out)
715{
716 // 4b. create a starting triangle
717 // 4b1. create all distances
718 DistanceMultiMap DistanceMMap;
719 double distance, tmp;
720 Vector PlaneVector, TrialVector;
721 PointMap::iterator A, B, C; // three nodes of the first triangle
722 A = PointsOnBoundary.begin(); // the first may be chosen arbitrarily
723
724 // with A chosen, take each pair B,C and sort
725 if (A != PointsOnBoundary.end()) {
726 B = A;
727 B++;
728 for (; B != PointsOnBoundary.end(); B++) {
729 C = B;
730 C++;
731 for (; C != PointsOnBoundary.end(); C++) {
732 tmp = A->second->node->x.Distance(&B->second->node->x);
733 distance = tmp*tmp;
734 tmp = A->second->node->x.Distance(&C->second->node->x);
735 distance += tmp*tmp;
736 tmp = B->second->node->x.Distance(&C->second->node->x);
737 distance += tmp*tmp;
738 DistanceMMap.insert( DistanceMultiMapPair(distance, pair<PointMap::iterator, PointMap::iterator>(B,C) ) );
739 }
740 }
741 }
742// // listing distances
743// *out << Verbose(1) << "Listing DistanceMMap:";
744// for(DistanceMultiMap::iterator runner = DistanceMMap.begin(); runner != DistanceMMap.end(); runner++) {
745// *out << " " << runner->first << "(" << *runner->second.first->second << ", " << *runner->second.second->second << ")";
746// }
747// *out << endl;
748
749 // 4b2. pick three baselines forming a triangle
750 // 1. we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
751 DistanceMultiMap::iterator baseline = DistanceMMap.begin();
752 for (; baseline != DistanceMMap.end(); baseline++) {
753 // we take from the smallest sum of squared distance as the base line BC (with peak A) onward as the triangle candidate
754 // 2. next, we have to check whether all points reside on only one side of the triangle
755 // 3. construct plane vector
756 PlaneVector.MakeNormalVector(&A->second->node->x, &baseline->second.first->second->node->x, &baseline->second.second->second->node->x);
757 *out << Verbose(2) << "Plane vector of candidate triangle is ";
758 PlaneVector.Output(out);
759 *out << endl;
760 // 4. loop over all points
761 double sign = 0.;
762 PointMap::iterator checker = PointsOnBoundary.begin();
763 for (; checker != PointsOnBoundary.end(); checker++) {
764 // (neglecting A,B,C)
765 if ((checker == A) || (checker == baseline->second.first) || (checker == baseline->second.second))
766 continue;
767 // 4a. project onto plane vector
768 TrialVector.CopyVector(&checker->second->node->x);
769 TrialVector.SubtractVector(&A->second->node->x);
770 distance = TrialVector.Projection(&PlaneVector);
771 if (fabs(distance) < 1e-4) // we need to have a small epsilon around 0 which is still ok
772 continue;
773 *out << Verbose(3) << "Projection of " << checker->second->node->Name << " yields distance of " << distance << "." << endl;
774 tmp = distance/fabs(distance);
775 // 4b. Any have different sign to than before? (i.e. would lie outside convex hull with this starting triangle)
776 if ((sign != 0) && (tmp != sign)) {
777 // 4c. If so, break 4. loop and continue with next candidate in 1. loop
778 *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;
779 break;
780 } else { // note the sign for later
781 *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;
782 sign = tmp;
783 }
784 // 4d. Check whether the point is inside the triangle (check distance to each node
785 tmp = checker->second->node->x.Distance(&A->second->node->x);
786 int innerpoint = 0;
787 if ((tmp < A->second->node->x.Distance(&baseline->second.first->second->node->x))
788 && (tmp < A->second->node->x.Distance(&baseline->second.second->second->node->x)))
789 innerpoint++;
790 tmp = checker->second->node->x.Distance(&baseline->second.first->second->node->x);
791 if ((tmp < baseline->second.first->second->node->x.Distance(&A->second->node->x))
792 && (tmp < baseline->second.first->second->node->x.Distance(&baseline->second.second->second->node->x)))
793 innerpoint++;
794 tmp = checker->second->node->x.Distance(&baseline->second.second->second->node->x);
795 if ((tmp < baseline->second.second->second->node->x.Distance(&baseline->second.first->second->node->x))
796 && (tmp < baseline->second.second->second->node->x.Distance(&A->second->node->x)))
797 innerpoint++;
798 // 4e. If so, break 4. loop and continue with next candidate in 1. loop
799 if (innerpoint == 3)
800 break;
801 }
802 // 5. come this far, all on same side? Then break 1. loop and construct triangle
803 if (checker == PointsOnBoundary.end()) {
804 *out << "Looks like we have a candidate!" << endl;
805 break;
806 }
807 }
808 if (baseline != DistanceMMap.end()) {
809 BPS[0] = baseline->second.first->second;
810 BPS[1] = baseline->second.second->second;
811 BLS[0] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
812 BPS[0] = A->second;
813 BPS[1] = baseline->second.second->second;
814 BLS[1] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
815 BPS[0] = baseline->second.first->second;
816 BPS[1] = A->second;
817 BLS[2] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
818
819 // 4b3. insert created triangle
820 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
821 TrianglesOnBoundary.insert( TrianglePair(TrianglesOnBoundaryCount, BTS) );
822 TrianglesOnBoundaryCount++;
823 for(int i=0;i<NDIM;i++) {
824 LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BTS->lines[i]) );
825 LinesOnBoundaryCount++;
826 }
827
828 *out << Verbose(1) << "Starting triangle is " << *BTS << "." << endl;
829 } else {
830 *out << Verbose(1) << "No starting triangle found." << endl;
831 exit(255);
832 }
833};
834
835
836/** Tesselates the convex envelope of a cluster from a single starting triangle.
837 * The starting triangle is made out of three baselines. Each line in the final tesselated cluster may belong to at most
838 * 2 triangles. Hence, we go through all current lines:
839 * -# if the lines contains to only one triangle
840 * -# We search all points in the boundary
841 * -# if the triangle with the baseline and the current point has the smallest of angles (comparison between normal vectors
842 * -# if the triangle is in forward direction of the baseline (at most 90 degrees angle between vector orthogonal to
843 * baseline in triangle plane pointing out of the triangle and normal vector of new triangle)
844 * -# then we have a new triangle, whose baselines we again add (or increase their TriangleCount)
845 * \param *out output stream for debugging
846 * \param *configuration for IsAngstroem
847 * \param *mol the cluster as a molecule structure
848 */
849void Tesselation::TesselateOnBoundary(ofstream *out, config *configuration, molecule *mol)
850{
851 bool flag;
852 PointMap::iterator winner;
853 class BoundaryPointSet *peak = NULL;
854 double SmallestAngle, TempAngle;
855 Vector NormalVector, VirtualNormalVector, CenterVector, TempVector, PropagationVector;
856 LineMap::iterator LineChecker[2];
857 do {
858 flag = false;
859 for (LineMap::iterator baseline = LinesOnBoundary.begin(); baseline != LinesOnBoundary.end(); baseline++)
860 if (baseline->second->TrianglesCount == 1) {
861 *out << Verbose(2) << "Current baseline is between " << *(baseline->second) << "." << endl;
862 // 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)
863 SmallestAngle = M_PI;
864 BTS = baseline->second->triangles.begin()->second; // there is only one triangle so far
865 // get peak point with respect to this base line's only triangle
866 for(int i=0;i<3;i++)
867 if ((BTS->endpoints[i] != baseline->second->endpoints[0]) && (BTS->endpoints[i] != baseline->second->endpoints[1]))
868 peak = BTS->endpoints[i];
869 *out << Verbose(3) << " and has peak " << *peak << "." << endl;
870 // normal vector of triangle
871 BTS->GetNormalVector(NormalVector);
872 *out << Verbose(4) << "NormalVector of base triangle is ";
873 NormalVector.Output(out);
874 *out << endl;
875 // offset to center of triangle
876 CenterVector.Zero();
877 for(int i=0;i<3;i++)
878 CenterVector.AddVector(&BTS->endpoints[i]->node->x);
879 CenterVector.Scale(1./3.);
880 *out << Verbose(4) << "CenterVector of base triangle is ";
881 CenterVector.Output(out);
882 *out << endl;
883 // vector in propagation direction (out of triangle)
884 // project center vector onto triangle plane (points from intersection plane-NormalVector to plane-CenterVector intersection)
885 TempVector.CopyVector(&baseline->second->endpoints[0]->node->x);
886 TempVector.SubtractVector(&baseline->second->endpoints[1]->node->x);
887 PropagationVector.MakeNormalVector(&TempVector, &NormalVector);
888 TempVector.CopyVector(&CenterVector);
889 TempVector.SubtractVector(&baseline->second->endpoints[0]->node->x); // TempVector is vector on triangle plane pointing from one baseline egde towards center!
890 //*out << Verbose(2) << "Projection of propagation onto temp: " << PropagationVector.Projection(&TempVector) << "." << endl;
891 if (PropagationVector.Projection(&TempVector) > 0) // make sure normal propagation vector points outward from baseline
892 PropagationVector.Scale(-1.);
893 *out << Verbose(4) << "PropagationVector of base triangle is ";
894 PropagationVector.Output(out);
895 *out << endl;
896 winner = PointsOnBoundary.end();
897 for (PointMap::iterator target = PointsOnBoundary.begin(); target != PointsOnBoundary.end(); target++)
898 if ((target->second != baseline->second->endpoints[0]) && (target->second != baseline->second->endpoints[1])) { // don't take the same endpoints
899 *out << Verbose(3) << "Target point is " << *(target->second) << ":";
900 bool continueflag = true;
901
902 VirtualNormalVector.CopyVector(&baseline->second->endpoints[0]->node->x);
903 VirtualNormalVector.AddVector(&baseline->second->endpoints[0]->node->x);
904 VirtualNormalVector.Scale(-1./2.); // points now to center of base line
905 VirtualNormalVector.AddVector(&target->second->node->x); // points from center of base line to target
906 TempAngle = VirtualNormalVector.Angle(&PropagationVector);
907 continueflag = continueflag && (TempAngle < (M_PI/2.)); // no bends bigger than Pi/2 (90 degrees)
908 if (!continueflag) {
909 *out << Verbose(4) << "Angle between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", bad direction!" << endl;
910 continue;
911 } else
912 *out << Verbose(4) << "Angle between propagation direction and base line to " << *(target->second) << " is " << TempAngle << ", good direction!" << endl;
913 LineChecker[0] = baseline->second->endpoints[0]->lines.find(target->first);
914 LineChecker[1] = baseline->second->endpoints[1]->lines.find(target->first);
915 // if (LineChecker[0] != baseline->second->endpoints[0]->lines.end())
916 // *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl;
917 // else
918 // *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has no line to " << *(target->second) << " as endpoint." << endl;
919 // if (LineChecker[1] != baseline->second->endpoints[1]->lines.end())
920 // *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl;
921 // else
922 // *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has no line to " << *(target->second) << " as endpoint." << endl;
923 // check first endpoint (if any connecting line goes to target or at least not more than 1)
924 continueflag = continueflag && (( (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) || (LineChecker[0]->second->TrianglesCount == 1)));
925 if (!continueflag) {
926 *out << Verbose(4) << *(baseline->second->endpoints[0]) << " has line " << *(LineChecker[0]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[0]->second->TrianglesCount << " triangles." << endl;
927 continue;
928 }
929 // check second endpoint (if any connecting line goes to target or at least not more than 1)
930 continueflag = continueflag && (( (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) || (LineChecker[1]->second->TrianglesCount == 1)));
931 if (!continueflag) {
932 *out << Verbose(4) << *(baseline->second->endpoints[1]) << " has line " << *(LineChecker[1]->second) << " to " << *(target->second) << " as endpoint with " << LineChecker[1]->second->TrianglesCount << " triangles." << endl;
933 continue;
934 }
935 // check whether the envisaged triangle does not already exist (if both lines exist and have same endpoint)
936 continueflag = continueflag && (!(
937 ((LineChecker[0] != baseline->second->endpoints[0]->lines.end()) && (LineChecker[1] != baseline->second->endpoints[1]->lines.end())
938 && (GetCommonEndpoint(LineChecker[0]->second, LineChecker[1]->second) == peak))
939 ));
940 if (!continueflag) {
941 *out << Verbose(4) << "Current target is peak!" << endl;
942 continue;
943 }
944 // in case NOT both were found
945 if (continueflag) { // create virtually this triangle, get its normal vector, calculate angle
946 flag = true;
947 VirtualNormalVector.MakeNormalVector(&baseline->second->endpoints[0]->node->x, &baseline->second->endpoints[1]->node->x, &target->second->node->x);
948 // make it always point inward
949 if (baseline->second->endpoints[0]->node->x.Projection(&VirtualNormalVector) > 0)
950 VirtualNormalVector.Scale(-1.);
951 // calculate angle
952 TempAngle = NormalVector.Angle(&VirtualNormalVector);
953 *out << Verbose(4) << "NormalVector is ";
954 VirtualNormalVector.Output(out);
955 *out << " and the angle is " << TempAngle << "." << endl;
956 if (SmallestAngle > TempAngle) { // set to new possible winner
957 SmallestAngle = TempAngle;
958 winner = target;
959 }
960 }
961 }
962 // 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
963 if (winner != PointsOnBoundary.end()) {
964 *out << Verbose(2) << "Winning target point is " << *(winner->second) << " with angle " << SmallestAngle << "." << endl;
965 // create the lins of not yet present
966 BLS[0] = baseline->second;
967 // 5c. add lines to the line set if those were new (not yet part of a triangle), delete lines that belong to two triangles)
968 LineChecker[0] = baseline->second->endpoints[0]->lines.find(winner->first);
969 LineChecker[1] = baseline->second->endpoints[1]->lines.find(winner->first);
970 if (LineChecker[0] == baseline->second->endpoints[0]->lines.end()) { // create
971 BPS[0] = baseline->second->endpoints[0];
972 BPS[1] = winner->second;
973 BLS[1] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
974 LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BLS[1]) );
975 LinesOnBoundaryCount++;
976 } else
977 BLS[1] = LineChecker[0]->second;
978 if (LineChecker[1] == baseline->second->endpoints[1]->lines.end()) { // create
979 BPS[0] = baseline->second->endpoints[1];
980 BPS[1] = winner->second;
981 BLS[2] = new class BoundaryLineSet(BPS, LinesOnBoundaryCount);
982 LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BLS[2]) );
983 LinesOnBoundaryCount++;
984 } else
985 BLS[2] = LineChecker[1]->second;
986 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
987 TrianglesOnBoundary.insert( TrianglePair(TrianglesOnBoundaryCount, BTS) );
988 TrianglesOnBoundaryCount++;
989 } else {
990 *out << Verbose(1) << "I could not determine a winner for this baseline " << *(baseline->second) << "." << endl;
991 }
992
993 // 5d. If the set of lines is not yet empty, go to 5. and continue
994 } else
995 *out << Verbose(2) << "Baseline candidate " << *(baseline->second) << " has a triangle count of " << baseline->second->TrianglesCount << "." << endl;
996 } while (flag);
997
998};
999
1000/** Adds an atom to the tesselation::PointsOnBoundary list.
1001 * \param *Walker atom to add
1002 */
1003void Tesselation::AddPoint(atom *Walker)
1004{
1005 PointTestPair InsertUnique;
1006 BPS[0] = new class BoundaryPointSet(Walker);
1007 InsertUnique = PointsOnBoundary.insert( PointPair(Walker->nr, BPS[0]) );
1008 if (InsertUnique.second) // if new point was not present before, increase counter
1009 PointsOnBoundaryCount++;
1010};
1011
1012
1013
1014
1015
1016
1017//====================================================================================================================
1018//
1019// ab hier habe ich das verzapft.
1020//
1021//====================================================================================================================
1022
1023
1024void Find_next_suitable_point(atom a, atom b, atom Candidate, int n, Vector *d1, Vector *d2, double *Storage, const double RADIUS, molecule mol)
1025{
1026 /* d2 ist der Normalenvektor auf dem Dreieck,
1027 * d1 ist der Vektor, der normal auf der Kante und d2 steht.
1028 */
1029 Vector dif_a;
1030 Vector dif_b;
1031 Vector Chord;
1032 Vector AngleCheck;
1033 atom *Walker;
1034
1035 dif_a.CopyVector(&a.x);
1036 dif_a.SubtractVector(&Candidate.x);
1037 dif_b.CopyVector(&b.x);
1038 dif_b.SubtractVector(&Candidate.x);
1039 Chord.CopyVector(&a.x);
1040 Chord.SubtractVector(&b.x);
1041 AngleCheck.CopyVector(&dif_a);
1042 AngleCheck.ProjectOntoPlane(&Chord);
1043
1044 //Storage eintrag fuer aktuelles Atom
1045 if (Chord.Norm()/(2*sin(dif_a.Angle(&dif_b)))<RADIUS) //Using Formula for relation of chord length with inner angle to find of Ball will touch atom
1046 {
1047
1048 if (dif_a.ScalarProduct(d1)/fabs(dif_a.ScalarProduct(d1))>Storage[1]) //This will give absolute preference to those in "right-hand" quadrants
1049 {
1050 Storage[0]=(double)Candidate.nr;
1051 Storage[1]=1;
1052 Storage[2]=AngleCheck.Angle(d2);
1053 }
1054 else
1055 {
1056 if ((dif_a.ScalarProduct(d1)/fabs(dif_a.ScalarProduct(d1)) == Storage[1] && Storage[1]>0 && Storage[2]< AngleCheck.Angle(d2)) or \
1057 (dif_a.ScalarProduct(d1)/fabs(dif_a.ScalarProduct(d1)) == Storage[1] && Storage[1]<0 && Storage[2]> AngleCheck.Angle(d2)))
1058 //Depending on quadrant we prefer higher or lower atom with respect to Triangle normal first.
1059 {
1060 Storage[0]=(double)Candidate.nr;
1061 Storage[1]=dif_a.ScalarProduct(d1)/fabs(dif_a.ScalarProduct(d1));
1062 Storage[2]=AngleCheck.Angle(d2);
1063 }
1064 }
1065 }
1066
1067 if (n<5)
1068 {
1069 for(int i=0; i<mol.NumberOfBondsPerAtom[Candidate.nr];i++)
1070 {
1071 while (Candidate.nr != (mol.ListOfBondsPerAtom[Candidate.nr][i]->leftatom->nr ==Candidate.nr ? mol.ListOfBondsPerAtom[Candidate.nr][i]->leftatom->nr : mol.ListOfBondsPerAtom[Candidate.nr][i]->rightatom->nr))
1072 {
1073 Walker = Walker->next;
1074 }
1075
1076 Find_next_suitable_point(a, b, *Walker, n+1, d1, d2, Storage, RADIUS, mol);
1077 }
1078 }
1079};
1080
1081
1082void Tesselation::Find_next_suitable_triangle(molecule *mol, BoundaryLineSet Line, BoundaryTriangleSet T, const double& RADIUS)
1083{
1084 Vector CenterOfLine = Line.endpoints[0]->node->x;
1085 Vector direction1;
1086 Vector direction2;
1087 Vector helper;
1088 atom* Walker;
1089
1090 double Storage[3];
1091 Storage[0]=-1.; // Id must be positive, we see should nothing be done
1092 Storage[1]=-1.; // This direction is either +1 or -1 one, so any result will take precedence over initial values
1093 Storage[2]=-10.; // This is also lower then any value produced by an eligible atom, which are all positive
1094
1095
1096 helper.CopyVector(&(Line.endpoints[0]->node->x));
1097 for (int i =0; i<3; i++)
1098 {
1099 if (T.endpoints[i]->node->nr != Line.endpoints[0]->node->nr && T.endpoints[i]->node->nr!=Line.endpoints[1]->node->nr)
1100 {
1101 helper.SubtractVector(&T.endpoints[i]->node->x);
1102 break;
1103 }
1104 }
1105
1106
1107 direction1.CopyVector(&Line.endpoints[0]->node->x);
1108 direction1.SubtractVector(&Line.endpoints[1]->node->x);
1109 direction1.VectorProduct(T.NormalVector);
1110
1111 if (direction1.ScalarProduct(&helper)>0)
1112 {
1113 direction1.Scale(-1);
1114 }
1115
1116 Find_next_suitable_point(*Line.endpoints[0]->node, *Line.endpoints[1]->node, *Line.endpoints[0]->node, 0, &direction1, T.NormalVector, Storage, RADIUS, *mol);
1117
1118 // Konstruiere nun neues Dreieck am Ende der Liste der Dreiecke
1119 // Next Triangle is Line, atom with number in Storage[0]
1120
1121 Walker= mol->start;
1122 while (Walker->nr != (int)Storage[0])
1123 {
1124 Walker = Walker->next;
1125 }
1126
1127 AddPoint(Walker);
1128
1129 BPS[0] = new class BoundaryPointSet(Walker);
1130 BPS[1] = new class BoundaryPointSet(Line.endpoints[0]->node);
1131 BLS[0] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
1132 BPS[0] = new class BoundaryPointSet(Walker);
1133 BPS[1] = new class BoundaryPointSet(Line.endpoints[1]->node);
1134 BLS[1] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
1135 BLS[2] = new class BoundaryLineSet(Line);
1136
1137 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1138 TrianglesOnBoundary.insert( TrianglePair(TrianglesOnBoundaryCount, BTS) );
1139 TrianglesOnBoundaryCount++;
1140
1141 for(int i=0;i<NDIM;i++) // sind Linien bereits vorhanden ???
1142 {
1143 if (LinesOnBoundary.find(BTS->lines[i]) == LinesOnBoundary.end)
1144 {
1145 LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BTS->lines[i]) );
1146 LinesOnBoundaryCount++;
1147 }
1148 }
1149 BTS->GetNormalVector(*BTS->NormalVector);
1150
1151 if( (BTS->NormalVector->ScalarProduct(T.NormalVector)<0 && Storage[1]>0) || \
1152 (BTS->NormalVector->ScalarProduct(T.NormalVector)>0 && Storage[1]<0))
1153 {
1154 BTS->NormalVector->Scale(-1);
1155 }
1156
1157};
1158
1159
1160void Find_second_point_for_Tesselation(atom a, atom Candidate, int n, Vector Oben, double* Storage, molecule mol)
1161{
1162 int i;
1163 Vector *AngleCheck;
1164 atom* Walker;
1165
1166 AngleCheck->CopyVector(&Candidate.x);
1167 AngleCheck->SubtractVector(&a.x);
1168 if (AngleCheck->ScalarProduct(&Oben) < Storage[1])
1169 {
1170 Storage[0]=(double)(Candidate.nr);
1171 Storage[1]=AngleCheck->ScalarProduct(&Oben);
1172 };
1173
1174 if (n<5)
1175 {
1176 for (i = 0; i< mol.NumberOfBondsPerAtom[Candidate.nr]; i++)
1177 {
1178 Walker = mol.start;
1179 while (Candidate.nr != (mol.ListOfBondsPerAtom[Candidate.nr][i]->leftatom->nr ==Candidate.nr ? mol.ListOfBondsPerAtom[Candidate.nr][i]->leftatom->nr : mol.ListOfBondsPerAtom[Candidate.nr][i]->rightatom->nr))
1180 {
1181 Walker = Walker->next;
1182 };
1183
1184 Find_second_point_for_Tesselation(a, *Walker, n+1, Oben, Storage, mol);
1185 };
1186 };
1187
1188
1189};
1190
1191
1192void Tesselation::Find_starting_triangle(molecule mol, const double RADIUS)
1193{
1194 int i=0;
1195 atom Walker;
1196 atom Walker2;
1197 atom Walker3;
1198 int max_index[3];
1199 double max_coordinate[3];
1200 Vector Oben;
1201 Vector helper;
1202
1203 Oben.Zero();
1204
1205
1206 for(i =0; i<3; i++)
1207 {
1208 max_index[i] =-1;
1209 max_coordinate[i] =-1;
1210 }
1211
1212 Walker = *mol.start;
1213 while (Walker.next != NULL)
1214 {
1215 for (i=0; i<3; i++)
1216 {
1217 if (Walker.x.x[i]>max_coordinate[i])
1218 {
1219 max_coordinate[i]=Walker.x.x[i];
1220 max_index[i]=Walker.nr;
1221 }
1222 }
1223 }
1224
1225 //Koennen dies fuer alle Richtungen, legen hier erstmal Richtung auf k=0
1226 const int k=0;
1227
1228 Oben.x[k]=1;
1229 Walker = *mol.start;
1230 while (Walker.nr != max_index[k])
1231 {
1232 Walker = *Walker.next;
1233 }
1234
1235 double Storage[3];
1236 Storage[0]=-1.; // Id must be positive, we see should nothing be done
1237 Storage[1]=-2.; // This will contain the angle, which will be always positive (when looking for second point), when looking for third point this will be the quadrant.
1238 Storage[2]=-10.; // This will be an angle looking for the third point.
1239
1240
1241 for (i=0; i< mol.NumberOfBondsPerAtom[Walker.nr]; i++)
1242 {
1243 Walker2 = *mol.start;
1244 while (Walker2.nr != (mol.ListOfBondsPerAtom[Walker.nr][i]->leftatom->nr == Walker.nr ? mol.ListOfBondsPerAtom[Walker.nr][i]->rightatom->nr : mol.ListOfBondsPerAtom[Walker.nr][i]->leftatom->nr) )
1245 {
1246 Walker2 = *Walker2.next;
1247 }
1248
1249 Find_second_point_for_Tesselation(Walker, Walker2, 0, Oben, Storage, mol);
1250 }
1251
1252 Walker2 = *mol.start;
1253
1254 while (Walker2.nr != int(Storage[0]))
1255 {
1256 Walker = *Walker.next;
1257 }
1258
1259 helper.CopyVector(&Walker.x);
1260 helper.SubtractVector(&Walker2.x);
1261 Oben.ProjectOntoPlane(&helper);
1262 helper.VectorProduct(&Oben);
1263
1264 Find_next_suitable_point(Walker, Walker2, *(mol.ListOfBondsPerAtom[Walker.nr][i]->leftatom->nr == Walker.nr ? mol.ListOfBondsPerAtom[Walker.nr][i]->rightatom : mol.ListOfBondsPerAtom[Walker.nr][i]->leftatom), 0, &helper, &Oben, Storage, RADIUS, mol);
1265 Walker3 = *mol.start;
1266 while (Walker3.nr != int(Storage[0]))
1267 {
1268 Walker3 = *Walker3.next;
1269 }
1270
1271 //Starting Triangle is Walker, Walker2, index Storage[0]
1272
1273 AddPoint(&Walker);
1274 AddPoint(&Walker2);
1275 AddPoint(&Walker3);
1276
1277 BPS[0] = new class BoundaryPointSet(&Walker);
1278 BPS[1] = new class BoundaryPointSet(&Walker2);
1279 BLS[0] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
1280 BPS[0] = new class BoundaryPointSet(&Walker);
1281 BPS[1] = new class BoundaryPointSet(&Walker3);
1282 BLS[1] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
1283 BPS[0] = new class BoundaryPointSet(&Walker);
1284 BPS[1] = new class BoundaryPointSet(&Walker2);
1285 BLS[2] = new class BoundaryLineSet(BPS , LinesOnBoundaryCount);
1286
1287 BTS = new class BoundaryTriangleSet(BLS, TrianglesOnBoundaryCount);
1288 TrianglesOnBoundary.insert( TrianglePair(TrianglesOnBoundaryCount, BTS) );
1289 TrianglesOnBoundaryCount++;
1290
1291 for(int i=0;i<NDIM;i++)
1292 {
1293 LinesOnBoundary.insert( LinePair(LinesOnBoundaryCount, BTS->lines[i]) );
1294 LinesOnBoundaryCount++;
1295 };
1296
1297 BTS->GetNormalVector(*BTS->NormalVector);
1298
1299 if( BTS->NormalVector->ScalarProduct(&Oben)<0)
1300 {
1301 BTS->NormalVector->Scale(-1);
1302 }
1303};
1304
1305
1306void Find_non_convex_border(Tesselation* Tess, molecule mol)
1307{
1308 const double RADIUS =6;
1309 Tess->Find_starting_triangle(mol, RADIUS);
1310
1311 for (LineMap::iterator baseline = Tess->LinesOnBoundary.begin(); baseline != Tess->LinesOnBoundary.end(); baseline++)
1312 if (baseline->second->TrianglesCount == 1)
1313 {
1314 Tess->Find_next_suitable_triangle(&mol, baseline->second, baseline->second->triangles.begin()->second, RADIUS); //the line is there, so there is a triangle, but only one.
1315
1316 }
1317 else
1318 {
1319 printf("There is a line with %d triangles adjacent", baseline->second->TrianglesCount);
1320 }
1321};
Note: See TracBrowser for help on using the repository browser.