source: src/boundary.cpp@ 8eb17a

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 8eb17a was 8eb17a, checked in by Frederik Heber <heber@…>, 17 years ago

StorePeriodentafel(): BUGFIX - there still was elements.db instead of define value

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