source: src/boundary.cpp@ ad37ab

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 Candidate_v1.7.0 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 ad37ab was ad37ab, checked in by Frederik Heber <heber@…>, 16 years ago

analyzer.cpp and boundary.cpp refactored.

  • ticket #39 is done with respect to these files
  • both do not contain member functions (anymore), hence ticket #4 and ticket #38 are both fulfilled.
  • Property mode set to 100755
File size: 48.2 KB
Line 
1/** \file boundary.cpp
2 *
3 * Implementations and super-function for envelopes
4 */
5
6#include "atom.hpp"
7#include "bond.hpp"
8#include "boundary.hpp"
9#include "config.hpp"
10#include "element.hpp"
11#include "helpers.hpp"
12#include "linkedcell.hpp"
13#include "memoryallocator.hpp"
14#include "molecule.hpp"
15#include "tesselation.hpp"
16#include "tesselationhelpers.hpp"
17
18#include<gsl/gsl_poly.h>
19
20// ========================================== F U N C T I O N S =================================
21
22
23/** Determines greatest diameters of a cluster defined by its convex envelope.
24 * Looks at lines parallel to one axis and where they intersect on the projected planes
25 * \param *out output stream for debugging
26 * \param *BoundaryPoints NDIM set of boundary points defining the convex envelope on each projected plane
27 * \param *mol molecule structure representing the cluster
28 * \param IsAngstroem whether we have angstroem or atomic units
29 * \return NDIM array of the diameters
30 */
31double *GetDiametersOfCluster(ofstream *out, Boundaries *BoundaryPtr, molecule *mol, bool IsAngstroem)
32{
33 // get points on boundary of NULL was given as parameter
34 bool BoundaryFreeFlag = false;
35 Boundaries *BoundaryPoints = BoundaryPtr;
36 double OldComponent = 0.;
37 double tmp = 0.;
38 double w1 = 0.;
39 double w2 = 0.;
40 Vector DistanceVector;
41 Vector OtherVector;
42 int component = 0;
43 int Othercomponent = 0;
44 Boundaries::iterator Neighbour;
45 Boundaries::iterator OtherNeighbour;
46 double *GreatestDiameter = new double[NDIM];
47
48 if (BoundaryPoints == NULL) {
49 BoundaryFreeFlag = true;
50 BoundaryPoints = GetBoundaryPoints(out, mol);
51 } else {
52 *out << Verbose(1) << "Using given boundary points set." << endl;
53 }
54 // determine biggest "diameter" of cluster for each axis
55 for (int i = 0; i < NDIM; i++)
56 GreatestDiameter[i] = 0.;
57 for (int axis = 0; axis < NDIM; axis++)
58 { // regard each projected plane
59 //*out << Verbose(1) << "Current axis is " << axis << "." << endl;
60 for (int j = 0; j < 2; j++)
61 { // and for both axis on the current plane
62 component = (axis + j + 1) % NDIM;
63 Othercomponent = (axis + 1 + ((j + 1) & 1)) % NDIM;
64 //*out << Verbose(1) << "Current component is " << component << ", Othercomponent is " << Othercomponent << "." << endl;
65 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner
66 != BoundaryPoints[axis].end(); runner++)
67 {
68 //*out << Verbose(2) << "Current runner is " << *(runner->second.second) << "." << endl;
69 // seek for the neighbours pair where the Othercomponent sign flips
70 Neighbour = runner;
71 Neighbour++;
72 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
73 Neighbour = BoundaryPoints[axis].begin();
74 DistanceVector.CopyVector(&runner->second.second->x);
75 DistanceVector.SubtractVector(&Neighbour->second.second->x);
76 do
77 { // seek for neighbour pair where it flips
78 OldComponent = DistanceVector.x[Othercomponent];
79 Neighbour++;
80 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
81 Neighbour = BoundaryPoints[axis].begin();
82 DistanceVector.CopyVector(&runner->second.second->x);
83 DistanceVector.SubtractVector(&Neighbour->second.second->x);
84 //*out << Verbose(3) << "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << "." << endl;
85 }
86 while ((runner != Neighbour) && (fabs(OldComponent / fabs(
87 OldComponent) - DistanceVector.x[Othercomponent] / fabs(
88 DistanceVector.x[Othercomponent])) < MYEPSILON)); // as long as sign does not flip
89 if (runner != Neighbour)
90 {
91 OtherNeighbour = Neighbour;
92 if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around
93 OtherNeighbour = BoundaryPoints[axis].end();
94 OtherNeighbour--;
95 //*out << Verbose(2) << "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << "." << endl;
96 // now we have found the pair: Neighbour and OtherNeighbour
97 OtherVector.CopyVector(&runner->second.second->x);
98 OtherVector.SubtractVector(&OtherNeighbour->second.second->x);
99 //*out << Verbose(2) << "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << "." << endl;
100 //*out << Verbose(2) << "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << "." << endl;
101 // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour
102 w1 = fabs(OtherVector.x[Othercomponent]);
103 w2 = fabs(DistanceVector.x[Othercomponent]);
104 tmp = fabs((w1 * DistanceVector.x[component] + w2
105 * OtherVector.x[component]) / (w1 + w2));
106 // mark if it has greater diameter
107 //*out << Verbose(2) << "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << "." << endl;
108 GreatestDiameter[component] = (GreatestDiameter[component]
109 > tmp) ? GreatestDiameter[component] : tmp;
110 } //else
111 //*out << Verbose(2) << "Saw no sign flip, probably top or bottom node." << endl;
112 }
113 }
114 }
115 *out << Verbose(0) << "RESULT: The biggest diameters are "
116 << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and "
117 << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom"
118 : "atomiclength") << "." << endl;
119
120 // free reference lists
121 if (BoundaryFreeFlag)
122 delete[] (BoundaryPoints);
123
124 return GreatestDiameter;
125}
126;
127
128
129/** Determines the boundary points of a cluster.
130 * Does a projection per axis onto the orthogonal plane, transforms into spherical coordinates, sorts them by the angle
131 * and looks at triples: if the middle has less a distance than the allowed maximum height of the triangle formed by the plane's
132 * center and first and last point in the triple, it is thrown out.
133 * \param *out output stream for debugging
134 * \param *mol molecule structure representing the cluster
135 */
136Boundaries *GetBoundaryPoints(ofstream *out, molecule *mol)
137{
138 atom *Walker = NULL;
139 PointMap PointsOnBoundary;
140 LineMap LinesOnBoundary;
141 TriangleMap TrianglesOnBoundary;
142 Vector *MolCenter = mol->DetermineCenterOfAll(out);
143 Vector helper;
144 BoundariesTestPair BoundaryTestPair;
145 Vector AxisVector;
146 Vector AngleReferenceVector;
147 Vector AngleReferenceNormalVector;
148 Vector ProjectedVector;
149 Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, nr)
150 double radius = 0.;
151 double angle = 0.;
152
153 *out << Verbose(1) << "Finding all boundary points." << endl;
154 // 3a. Go through every axis
155 for (int axis = 0; axis < NDIM; axis++) {
156 AxisVector.Zero();
157 AngleReferenceVector.Zero();
158 AngleReferenceNormalVector.Zero();
159 AxisVector.x[axis] = 1.;
160 AngleReferenceVector.x[(axis + 1) % NDIM] = 1.;
161 AngleReferenceNormalVector.x[(axis + 2) % NDIM] = 1.;
162
163 *out << Verbose(1) << "Axisvector is " << AxisVector << " and AngleReferenceVector is " << AngleReferenceVector << ", and AngleReferenceNormalVector is " << AngleReferenceNormalVector << "." << endl;
164
165 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
166 Walker = mol->start;
167 while (Walker->next != mol->end) {
168 Walker = Walker->next;
169 ProjectedVector.CopyVector(&Walker->x);
170 ProjectedVector.SubtractVector(MolCenter);
171 ProjectedVector.ProjectOntoPlane(&AxisVector);
172
173 // correct for negative side
174 radius = ProjectedVector.NormSquared();
175 if (fabs(radius) > MYEPSILON)
176 angle = ProjectedVector.Angle(&AngleReferenceVector);
177 else
178 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
179
180 //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl;
181 if (ProjectedVector.ScalarProduct(&AngleReferenceNormalVector) > 0) {
182 angle = 2. * M_PI - angle;
183 }
184 *out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): " << ProjectedVector << endl;
185 BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle, DistancePair (radius, Walker)));
186 if (!BoundaryTestPair.second) { // same point exists, check first r, then distance of original vectors to center of gravity
187 *out << Verbose(2) << "Encountered two vectors whose projection onto axis " << axis << " is equal: " << endl;
188 *out << Verbose(2) << "Present vector: " << *BoundaryTestPair.first->second.second << endl;
189 *out << Verbose(2) << "New vector: " << *Walker << endl;
190 double tmp = ProjectedVector.NormSquared();
191 if ((tmp - BoundaryTestPair.first->second.first) > MYEPSILON) {
192 BoundaryTestPair.first->second.first = tmp;
193 BoundaryTestPair.first->second.second = Walker;
194 *out << Verbose(2) << "Keeping new vector due to larger projected distance " << tmp << "." << endl;
195 } else if (fabs(tmp - BoundaryTestPair.first->second.first) < MYEPSILON) {
196 helper.CopyVector(&Walker->x);
197 helper.SubtractVector(MolCenter);
198 tmp = helper.NormSquared();
199 helper.CopyVector(&BoundaryTestPair.first->second.second->x);
200 helper.SubtractVector(MolCenter);
201 if (helper.NormSquared() < tmp) {
202 BoundaryTestPair.first->second.second = Walker;
203 *out << Verbose(2) << "Keeping new vector due to larger distance to molecule center " << helper.NormSquared() << "." << endl;
204 } else {
205 *out << Verbose(2) << "Keeping present vector due to larger distance to molecule center " << tmp << "." << endl;
206 }
207 } else {
208 *out << Verbose(2) << "Keeping present vector due to larger projected distance " << tmp << "." << endl;
209 }
210 }
211 }
212 // printing all inserted for debugging
213 // {
214 // *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
215 // int i=0;
216 // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
217 // if (runner != BoundaryPoints[axis].begin())
218 // *out << ", " << i << ": " << *runner->second.second;
219 // else
220 // *out << i << ": " << *runner->second.second;
221 // i++;
222 // }
223 // *out << endl;
224 // }
225 // 3c. throw out points whose distance is less than the mean of left and right neighbours
226 bool flag = false;
227 *out << Verbose(1) << "Looking for candidates to kick out by convex condition ... " << endl;
228 do { // do as long as we still throw one out per round
229 flag = false;
230 Boundaries::iterator left = BoundaryPoints[axis].end();
231 Boundaries::iterator right = BoundaryPoints[axis].end();
232 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
233 // set neighbours correctly
234 if (runner == BoundaryPoints[axis].begin()) {
235 left = BoundaryPoints[axis].end();
236 } else {
237 left = runner;
238 }
239 left--;
240 right = runner;
241 right++;
242 if (right == BoundaryPoints[axis].end()) {
243 right = BoundaryPoints[axis].begin();
244 }
245 // check distance
246
247 // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)
248 {
249 Vector SideA, SideB, SideC, SideH;
250 SideA.CopyVector(&left->second.second->x);
251 SideA.SubtractVector(MolCenter);
252 SideA.ProjectOntoPlane(&AxisVector);
253 // *out << "SideA: ";
254 // SideA.Output(out);
255 // *out << endl;
256
257 SideB.CopyVector(&right->second.second->x);
258 SideB.SubtractVector(MolCenter);
259 SideB.ProjectOntoPlane(&AxisVector);
260 // *out << "SideB: ";
261 // SideB.Output(out);
262 // *out << endl;
263
264 SideC.CopyVector(&left->second.second->x);
265 SideC.SubtractVector(&right->second.second->x);
266 SideC.ProjectOntoPlane(&AxisVector);
267 // *out << "SideC: ";
268 // SideC.Output(out);
269 // *out << endl;
270
271 SideH.CopyVector(&runner->second.second->x);
272 SideH.SubtractVector(MolCenter);
273 SideH.ProjectOntoPlane(&AxisVector);
274 // *out << "SideH: ";
275 // SideH.Output(out);
276 // *out << endl;
277
278 // calculate each length
279 const double a = SideA.Norm();
280 //const double b = SideB.Norm();
281 //const double c = SideC.Norm();
282 const double h = SideH.Norm();
283 // calculate the angles
284 const double alpha = SideA.Angle(&SideH);
285 const double beta = SideA.Angle(&SideC);
286 const double gamma = SideB.Angle(&SideH);
287 const double delta = SideC.Angle(&SideH);
288 const double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.);
289 //*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;
290 *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;
291 if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance)) < MYEPSILON) && ((h - MinDistance)) < -MYEPSILON) {
292 // throw out point
293 *out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl;
294 BoundaryPoints[axis].erase(runner);
295 flag = true;
296 }
297 }
298 }
299 } while (flag);
300 }
301 delete(MolCenter);
302 return BoundaryPoints;
303};
304
305/** Tesselates the convex boundary by finding all boundary points.
306 * \param *out output stream for debugging
307 * \param *mol molecule structure with Atom's and Bond's
308 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
309 * \param *LCList atoms in LinkedCell list
310 * \param *filename filename prefix for output of vertex data
311 * \return *TesselStruct is filled with convex boundary and tesselation is stored under \a *filename.
312 */
313void FindConvexBorder(ofstream *out, molecule* mol, class LinkedCell *LCList, const char *filename)
314{
315 bool BoundaryFreeFlag = false;
316 Boundaries *BoundaryPoints = NULL;
317
318 cout << Verbose(1) << "Begin of FindConvexBorder" << endl;
319
320 if (mol->TesselStruct != NULL) // free if allocated
321 delete(mol->TesselStruct);
322 mol->TesselStruct = new class Tesselation;
323
324 // 1. Find all points on the boundary
325 if (BoundaryPoints == NULL) {
326 BoundaryFreeFlag = true;
327 BoundaryPoints = GetBoundaryPoints(out, mol);
328 } else {
329 *out << Verbose(1) << "Using given boundary points set." << endl;
330 }
331
332// printing all inserted for debugging
333 for (int axis=0; axis < NDIM; axis++)
334 {
335 *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
336 int i=0;
337 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
338 if (runner != BoundaryPoints[axis].begin())
339 *out << ", " << i << ": " << *runner->second.second;
340 else
341 *out << i << ": " << *runner->second.second;
342 i++;
343 }
344 *out << endl;
345 }
346
347 // 2. fill the boundary point list
348 for (int axis = 0; axis < NDIM; axis++)
349 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++)
350 if (!mol->TesselStruct->AddBoundaryPoint(runner->second.second, 0))
351 *out << Verbose(3) << "WARNING: Point " << *(runner->second.second) << " is already present!" << endl;
352
353 *out << Verbose(2) << "I found " << mol->TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl;
354 // now we have the whole set of edge points in the BoundaryList
355
356 // listing for debugging
357 // *out << Verbose(1) << "Listing PointsOnBoundary:";
358 // for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
359 // *out << " " << *runner->second;
360 // }
361 // *out << endl;
362
363 // 3a. guess starting triangle
364 mol->TesselStruct->GuessStartingTriangle(out);
365
366 // 3b. go through all lines, that are not yet part of two triangles (only of one so far)
367 mol->TesselStruct->TesselateOnBoundary(out, mol);
368
369 // 3c. check whether all atoms lay inside the boundary, if not, add to boundary points, segment triangle into three with the new point
370 if (!mol->TesselStruct->InsertStraddlingPoints(out, mol, LCList))
371 *out << Verbose(1) << "Insertion of straddling points failed!" << endl;
372
373 *out << Verbose(2) << "I created " << mol->TesselStruct->TrianglesOnBoundary.size() << " intermediate triangles with " << mol->TesselStruct->LinesOnBoundary.size() << " lines and " << mol->TesselStruct->PointsOnBoundary.size() << " points." << endl;
374
375 // 4. Store triangles in tecplot file
376 if (filename != NULL) {
377 if (DoTecplotOutput) {
378 string OutputName(filename);
379 OutputName.append("_intermed");
380 OutputName.append(TecplotSuffix);
381 ofstream *tecplot = new ofstream(OutputName.c_str());
382 WriteTecplotFile(out, tecplot, mol->TesselStruct, mol, 0);
383 tecplot->close();
384 delete(tecplot);
385 }
386 if (DoRaster3DOutput) {
387 string OutputName(filename);
388 OutputName.append("_intermed");
389 OutputName.append(Raster3DSuffix);
390 ofstream *rasterplot = new ofstream(OutputName.c_str());
391 WriteRaster3dFile(out, rasterplot, mol->TesselStruct, mol);
392 rasterplot->close();
393 delete(rasterplot);
394 }
395 }
396
397 // 3d. check all baselines whether the peaks of the two adjacent triangles with respect to center of baseline are convex, if not, make the baseline between the two peaks and baseline endpoints become the new peaks
398 bool AllConvex = true;
399 class BoundaryLineSet *line = NULL;
400 do {
401 AllConvex = true;
402 for (LineMap::iterator LineRunner = mol->TesselStruct->LinesOnBoundary.begin(); LineRunner != mol->TesselStruct->LinesOnBoundary.end(); LineRunner++) {
403 line = LineRunner->second;
404 *out << Verbose(1) << "INFO: Current line is " << *line << "." << endl;
405 if (!line->CheckConvexityCriterion(out)) {
406 *out << Verbose(1) << "... line " << *line << " is concave, flipping it." << endl;
407
408 // flip the line
409 if (mol->TesselStruct->PickFarthestofTwoBaselines(out, line) == 0.)
410 *out << Verbose(1) << "ERROR: Correction of concave baselines failed!" << endl;
411 else {
412 mol->TesselStruct->FlipBaseline(out, line);
413 *out << Verbose(1) << "INFO: Correction of concave baselines worked." << endl;
414 }
415 }
416 }
417 } while (!AllConvex);
418
419 // 3e. we need another correction here, for TesselPoints that are below the surface (i.e. have an odd number of concave triangles surrounding it)
420// if (!mol->TesselStruct->CorrectConcaveTesselPoints(out))
421// *out << Verbose(1) << "Correction of concave tesselpoints failed!" << endl;
422
423 *out << Verbose(2) << "I created " << mol->TesselStruct->TrianglesOnBoundary.size() << " triangles with " << mol->TesselStruct->LinesOnBoundary.size() << " lines and " << mol->TesselStruct->PointsOnBoundary.size() << " points." << endl;
424
425 // 4. Store triangles in tecplot file
426 if (filename != NULL) {
427 if (DoTecplotOutput) {
428 string OutputName(filename);
429 OutputName.append(TecplotSuffix);
430 ofstream *tecplot = new ofstream(OutputName.c_str());
431 WriteTecplotFile(out, tecplot, mol->TesselStruct, mol, 0);
432 tecplot->close();
433 delete(tecplot);
434 }
435 if (DoRaster3DOutput) {
436 string OutputName(filename);
437 OutputName.append(Raster3DSuffix);
438 ofstream *rasterplot = new ofstream(OutputName.c_str());
439 WriteRaster3dFile(out, rasterplot, mol->TesselStruct, mol);
440 rasterplot->close();
441 delete(rasterplot);
442 }
443 }
444
445
446 // free reference lists
447 if (BoundaryFreeFlag)
448 delete[] (BoundaryPoints);
449
450 cout << Verbose(1) << "End of FindConvexBorder" << endl;
451};
452
453/** For testing removes one boundary point after another to check for leaks.
454 * \param *out output stream for debugging
455 * \param *TesselStruct Tesselation containing envelope with boundary points
456 * \param *mol molecule
457 * \param *filename name of file
458 * \return true - all removed, false - something went wrong
459 */
460bool RemoveAllBoundaryPoints(ofstream *out, class Tesselation *TesselStruct, molecule *mol, char *filename)
461{
462 int i=0;
463 char number[MAXSTRINGSIZE];
464
465 if ((TesselStruct == NULL) || (TesselStruct->PointsOnBoundary.empty())) {
466 *out << Verbose(2) << "ERROR: TesselStruct is empty." << endl;
467 return false;
468 }
469
470 PointMap::iterator PointRunner;
471 while (!TesselStruct->PointsOnBoundary.empty()) {
472 *out << Verbose(2) << "Remaining points are: ";
473 for (PointMap::iterator PointSprinter = TesselStruct->PointsOnBoundary.begin(); PointSprinter != TesselStruct->PointsOnBoundary.end(); PointSprinter++)
474 *out << *(PointSprinter->second) << "\t";
475 *out << endl;
476
477 PointRunner = TesselStruct->PointsOnBoundary.begin();
478 // remove point
479 TesselStruct->RemovePointFromTesselatedSurface(out, PointRunner->second);
480
481 // store envelope
482 sprintf(number, "-%04d", i++);
483 StoreTrianglesinFile(out, mol, filename, number);
484 }
485
486 return true;
487};
488
489/** Creates a convex envelope from a given non-convex one.
490 * -# First step, remove concave spots, i.e. singular "dents"
491 * -# We go through all PointsOnBoundary.
492 * -# We CheckConvexityCriterion() for all its lines.
493 * -# If all its lines are concave, it cannot be on the convex envelope.
494 * -# Hence, we remove it and re-create all its triangles from its getCircleOfConnectedPoints()
495 * -# We calculate the additional volume.
496 * -# We go over all lines until none yields a concavity anymore.
497 * -# Second step, remove concave lines, i.e. line-shape "dents"
498 * -# We go through all LinesOnBoundary
499 * -# We CheckConvexityCriterion()
500 * -# If it returns concave, we flip the line in this quadrupel of points (abusing the degeneracy of the tesselation)
501 * -# We CheckConvexityCriterion(),
502 * -# if it's concave, we continue
503 * -# if not, we mark an error and stop
504 * Note: This routine - for free - calculates the difference in volume between convex and
505 * non-convex envelope, as the former is easy to calculate - VolumeOfConvexEnvelope() - it
506 * can be used to compute volumes of arbitrary shapes.
507 * \param *out output stream for debugging
508 * \param *TesselStruct non-convex envelope, is changed in return!
509 * \param *mol molecule
510 * \param *filename name of file
511 * \return volume difference between the non- and the created convex envelope
512 */
513double ConvexizeNonconvexEnvelope(ofstream *out, class Tesselation *TesselStruct, molecule *mol, char *filename)
514{
515 double volume = 0;
516 class BoundaryPointSet *point = NULL;
517 class BoundaryLineSet *line = NULL;
518 bool Concavity = false;
519 char dummy[MAXSTRINGSIZE];
520 PointMap::iterator PointRunner;
521 PointMap::iterator PointAdvance;
522 LineMap::iterator LineRunner;
523 LineMap::iterator LineAdvance;
524 TriangleMap::iterator TriangleRunner;
525 TriangleMap::iterator TriangleAdvance;
526 int run = 0;
527
528 *out << Verbose(0) << "Begin of ConvexizeNonconvexEnvelope" << endl;
529
530 // check whether there is something to work on
531 if (TesselStruct == NULL) {
532 *out << Verbose(1) << "ERROR: TesselStruct is empty!" << endl;
533 return volume;
534 }
535
536 // First step: RemovePointFromTesselatedSurface
537 do {
538 Concavity = false;
539 sprintf(dummy, "-first-%d", run);
540 //CalculateConcavityPerBoundaryPoint(out, TesselStruct);
541 StoreTrianglesinFile(out, mol, filename, dummy);
542
543 PointRunner = TesselStruct->PointsOnBoundary.begin();
544 PointAdvance = PointRunner; // we need an advanced point, as the PointRunner might get removed
545 while (PointRunner != TesselStruct->PointsOnBoundary.end()) {
546 PointAdvance++;
547 point = PointRunner->second;
548 *out << Verbose(1) << "INFO: Current point is " << *point << "." << endl;
549 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++) {
550 line = LineRunner->second;
551 *out << Verbose(2) << "INFO: Current line of point " << *point << " is " << *line << "." << endl;
552 if (!line->CheckConvexityCriterion(out)) {
553 // remove the point if needed
554 *out << Verbose(1) << "... point " << *point << " cannot be on convex envelope." << endl;
555 volume += TesselStruct->RemovePointFromTesselatedSurface(out, point);
556 sprintf(dummy, "-first-%d", ++run);
557 StoreTrianglesinFile(out, mol, filename, dummy);
558 Concavity = true;
559 break;
560 }
561 }
562 PointRunner = PointAdvance;
563 }
564
565 sprintf(dummy, "-second-%d", run);
566 //CalculateConcavityPerBoundaryPoint(out, TesselStruct);
567 StoreTrianglesinFile(out, mol, filename, dummy);
568
569 // second step: PickFarthestofTwoBaselines
570 LineRunner = TesselStruct->LinesOnBoundary.begin();
571 LineAdvance = LineRunner; // we need an advanced line, as the LineRunner might get removed
572 while (LineRunner != TesselStruct->LinesOnBoundary.end()) {
573 LineAdvance++;
574 line = LineRunner->second;
575 *out << Verbose(1) << "INFO: Picking farthest baseline for line is " << *line << "." << endl;
576 // take highest of both lines
577 if (TesselStruct->IsConvexRectangle(out, line) == NULL) {
578 const double tmp = TesselStruct->PickFarthestofTwoBaselines(out, line);
579 volume += tmp;
580 if (tmp != 0.) {
581 mol->TesselStruct->FlipBaseline(out, line);
582 Concavity = true;
583 }
584 }
585 LineRunner = LineAdvance;
586 }
587 run++;
588 } while (Concavity);
589 //CalculateConcavityPerBoundaryPoint(out, TesselStruct);
590 //StoreTrianglesinFile(out, mol, filename, "-third");
591
592 // third step: IsConvexRectangle
593// LineRunner = TesselStruct->LinesOnBoundary.begin();
594// LineAdvance = LineRunner; // we need an advanced line, as the LineRunner might get removed
595// while (LineRunner != TesselStruct->LinesOnBoundary.end()) {
596// LineAdvance++;
597// line = LineRunner->second;
598// *out << Verbose(1) << "INFO: Current line is " << *line << "." << endl;
599// //if (LineAdvance != TesselStruct->LinesOnBoundary.end())
600// //*out << Verbose(1) << "INFO: Next line will be " << *(LineAdvance->second) << "." << endl;
601// if (!line->CheckConvexityCriterion(out)) {
602// *out << Verbose(1) << "... line " << *line << " is concave, flipping it." << endl;
603//
604// // take highest of both lines
605// point = TesselStruct->IsConvexRectangle(out, line);
606// if (point != NULL)
607// volume += TesselStruct->RemovePointFromTesselatedSurface(out, point);
608// }
609// LineRunner = LineAdvance;
610// }
611
612 CalculateConcavityPerBoundaryPoint(out, TesselStruct);
613 StoreTrianglesinFile(out, mol, filename, "");
614
615 // end
616 *out << Verbose(1) << "Volume is " << volume << "." << endl;
617 *out << Verbose(0) << "End of ConvexizeNonconvexEnvelope" << endl;
618 return volume;
619};
620
621
622/** Determines the volume of a cluster.
623 * Determines first the convex envelope, then tesselates it and calculates its volume.
624 * \param *out output stream for debugging
625 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
626 * \param *configuration needed for path to store convex envelope file
627 * \return determined volume of the cluster in cubed config:GetIsAngstroem()
628 */
629double VolumeOfConvexEnvelope(ofstream *out, class Tesselation *TesselStruct, class config *configuration)
630{
631 bool IsAngstroem = configuration->GetIsAngstroem();
632 double volume = 0.;
633 Vector x;
634 Vector y;
635
636 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
637 *out << Verbose(1)
638 << "Calculating the volume of the pyramids formed out of triangles and center of gravity."
639 << endl;
640 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++)
641 { // go through every triangle, calculate volume of its pyramid with CoG as peak
642 x.CopyVector(runner->second->endpoints[0]->node->node);
643 x.SubtractVector(runner->second->endpoints[1]->node->node);
644 y.CopyVector(runner->second->endpoints[0]->node->node);
645 y.SubtractVector(runner->second->endpoints[2]->node->node);
646 const double a = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
647 const double b = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[2]->node->node));
648 const double c = sqrt(runner->second->endpoints[2]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
649 const double G = sqrt(((a + b + c) * (a + b + c) - 2 * (a * a + b * b + c * c)) / 16.); // area of tesselated triangle
650 x.MakeNormalVector(runner->second->endpoints[0]->node->node, runner->second->endpoints[1]->node->node, runner->second->endpoints[2]->node->node);
651 x.Scale(runner->second->endpoints[1]->node->node->ScalarProduct(&x));
652 const double h = x.Norm(); // distance of CoG to triangle
653 const double PyramidVolume = (1. / 3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
654 *out << Verbose(2) << "Area of triangle is " << G << " "
655 << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is "
656 << h << " and the volume is " << PyramidVolume << " "
657 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
658 volume += PyramidVolume;
659 }
660 *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10)
661 << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3."
662 << endl;
663
664 return volume;
665};
666
667/** Stores triangles to file.
668 * \param *out output stream for debugging
669 * \param *mol molecule with atoms and bonds
670 * \param *filename prefix of filename
671 * \param *extraSuffix intermediate suffix
672 */
673void StoreTrianglesinFile(ofstream *out, molecule *mol, const char *filename, const char *extraSuffix)
674{
675 // 4. Store triangles in tecplot file
676 if (filename != NULL) {
677 if (DoTecplotOutput) {
678 string OutputName(filename);
679 OutputName.append(extraSuffix);
680 OutputName.append(TecplotSuffix);
681 ofstream *tecplot = new ofstream(OutputName.c_str());
682 WriteTecplotFile(out, tecplot, mol->TesselStruct, mol, 0);
683 tecplot->close();
684 delete(tecplot);
685 }
686 if (DoRaster3DOutput) {
687 string OutputName(filename);
688 OutputName.append(extraSuffix);
689 OutputName.append(Raster3DSuffix);
690 ofstream *rasterplot = new ofstream(OutputName.c_str());
691 WriteRaster3dFile(out, rasterplot, mol->TesselStruct, mol);
692 rasterplot->close();
693 delete(rasterplot);
694 }
695 }
696};
697
698/** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
699 * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
700 * \param *out output stream for debugging
701 * \param *configuration needed for path to store convex envelope file
702 * \param *mol molecule structure representing the cluster
703 * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead.
704 * \param celldensity desired average density in final cell
705 */
706void PrepareClustersinWater(ofstream *out, config *configuration, molecule *mol, double ClusterVolume, double celldensity)
707{
708 bool IsAngstroem = NULL;
709 double *GreatestDiameter = NULL;
710 Boundaries *BoundaryPoints = NULL;
711 class Tesselation *TesselStruct = NULL;
712 Vector BoxLengths;
713 int repetition[NDIM] = { 1, 1, 1 };
714 int TotalNoClusters = 1;
715 atom *Walker = NULL;
716 double totalmass = 0.;
717 double clustervolume = 0.;
718 double cellvolume = 0.;
719
720 // transform to PAS
721 mol->PrincipalAxisSystem(out, true);
722
723 IsAngstroem = configuration->GetIsAngstroem();
724 GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, IsAngstroem);
725 BoundaryPoints = GetBoundaryPoints(out, mol);
726 LinkedCell LCList(mol, 10.);
727 FindConvexBorder(out, mol, &LCList, NULL);
728
729 // some preparations beforehand
730 if (ClusterVolume == 0)
731 clustervolume = VolumeOfConvexEnvelope(out, TesselStruct, configuration);
732 else
733 clustervolume = ClusterVolume;
734
735 for (int i = 0; i < NDIM; i++)
736 TotalNoClusters *= repetition[i];
737
738 // sum up the atomic masses
739 Walker = mol->start;
740 while (Walker->next != mol->end) {
741 Walker = Walker->next;
742 totalmass += Walker->type->mass;
743 }
744 *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10) << totalmass << " atomicmassunit." << endl;
745 *out << Verbose(0) << "RESULT: The average density is " << setprecision(10) << totalmass / clustervolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
746
747 // solve cubic polynomial
748 *out << Verbose(1) << "Solving equidistant suspension in water problem ..." << endl;
749 if (IsAngstroem)
750 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_A - (totalmass / clustervolume)) / (celldensity - 1);
751 else
752 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_a0 - (totalmass / clustervolume)) / (celldensity - 1);
753 *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
754
755 double minimumvolume = TotalNoClusters * (GreatestDiameter[0] * GreatestDiameter[1] * GreatestDiameter[2]);
756 *out << Verbose(1) << "Minimum volume of the convex envelope contained in a rectangular box is " << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
757 if (minimumvolume > cellvolume) {
758 cerr << Verbose(0) << "ERROR: the containing box already has a greater volume than the envisaged cell volume!" << endl;
759 cout << Verbose(0) << "Setting Box dimensions to minimum possible, the greatest diameters." << endl;
760 for (int i = 0; i < NDIM; i++)
761 BoxLengths.x[i] = GreatestDiameter[i];
762 mol->CenterEdge(out, &BoxLengths);
763 } else {
764 BoxLengths.x[0] = (repetition[0] * GreatestDiameter[0] + repetition[1] * GreatestDiameter[1] + repetition[2] * GreatestDiameter[2]);
765 BoxLengths.x[1] = (repetition[0] * repetition[1] * GreatestDiameter[0] * GreatestDiameter[1] + repetition[0] * repetition[2] * GreatestDiameter[0] * GreatestDiameter[2] + repetition[1] * repetition[2] * GreatestDiameter[1] * GreatestDiameter[2]);
766 BoxLengths.x[2] = minimumvolume - cellvolume;
767 double x0 = 0.;
768 double x1 = 0.;
769 double x2 = 0.;
770 if (gsl_poly_solve_cubic(BoxLengths.x[0], BoxLengths.x[1], BoxLengths.x[2], &x0, &x1, &x2) == 1) // either 1 or 3 on return
771 *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0 << " ." << endl;
772 else {
773 *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0 << " and " << x1 << " and " << x2 << " ." << endl;
774 x0 = x2; // sorted in ascending order
775 }
776
777 cellvolume = 1.;
778 for (int i = 0; i < NDIM; i++) {
779 BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]);
780 cellvolume *= BoxLengths.x[i];
781 }
782
783 // set new box dimensions
784 *out << Verbose(0) << "Translating to box with these boundaries." << endl;
785 mol->SetBoxDimension(&BoxLengths);
786 mol->CenterInBox((ofstream *) &cout);
787 }
788 // update Box of atoms by boundary
789 mol->SetBoxDimension(&BoxLengths);
790 *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;
791};
792
793
794/** Fills the empty space of the simulation box with water/
795 * \param *out output stream for debugging
796 * \param *List list of molecules already present in box
797 * \param *TesselStruct contains tesselated surface
798 * \param *filler molecule which the box is to be filled with
799 * \param configuration contains box dimensions
800 * \param distance[NDIM] distance between filling molecules in each direction
801 * \param RandAtomDisplacement maximum distance for random displacement per atom
802 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
803 * \param DoRandomRotation true - do random rotiations, false - don't
804 * \return *mol pointer to new molecule with filled atoms
805 */
806molecule * FillBoxWithMolecule(ofstream *out, MoleculeListClass *List, molecule *filler, config &configuration, double distance[NDIM], double RandomAtomDisplacement, double RandomMolDisplacement, bool DoRandomRotation)
807{
808 molecule *Filling = new molecule(filler->elemente);
809 Vector CurrentPosition;
810 int N[NDIM];
811 int n[NDIM];
812 double *M = ReturnFullMatrixforSymmetric(filler->cell_size);
813 double Rotations[NDIM*NDIM];
814 Vector AtomTranslations;
815 Vector FillerTranslations;
816 Vector FillerDistance;
817 double FillIt = false;
818 atom *Walker = NULL;
819 bond *Binder = NULL;
820 int i = 0;
821 LinkedCell *LCList[List->ListOfMolecules.size()];
822 double phi[NDIM];
823
824 *out << Verbose(0) << "Begin of FillBoxWithMolecule" << endl;
825
826 i=0;
827 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
828 *out << Verbose(1) << "Pre-creating linked cell lists for molecule " << *ListRunner << "." << endl;
829 LCList[i] = new LinkedCell((*ListRunner), 5.); // get linked cell list
830 if ((*ListRunner)->TesselStruct == NULL) {
831 *out << Verbose(1) << "Pre-creating tesselation for molecule " << *ListRunner << "." << endl;
832 FindNonConvexBorder((ofstream *)&cout, (*ListRunner), LCList[i], 5., NULL);
833 }
834 i++;
835 }
836
837 // Center filler at origin
838 filler->CenterOrigin(out);
839 filler->Center.Zero();
840
841 filler->CountAtoms(out);
842 atom * CopyAtoms[filler->AtomCount];
843
844 // calculate filler grid in [0,1]^3
845 FillerDistance.Init(distance[0], distance[1], distance[2]);
846 FillerDistance.InverseMatrixMultiplication(M);
847 *out << Verbose(1) << "INFO: Grid steps are ";
848 for(int i=0;i<NDIM;i++) {
849 N[i] = (int) ceil(1./FillerDistance.x[i]);
850 *out << N[i];
851 if (i != NDIM-1)
852 *out<< ", ";
853 else
854 *out << "." << endl;
855 }
856
857 // go over [0,1]^3 filler grid
858 for (n[0] = 0; n[0] < N[0]; n[0]++)
859 for (n[1] = 0; n[1] < N[1]; n[1]++)
860 for (n[2] = 0; n[2] < N[2]; n[2]++) {
861 // calculate position of current grid vector in untransformed box
862 CurrentPosition.Init((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
863 CurrentPosition.MatrixMultiplication(M);
864 *out << Verbose(2) << "INFO: Current Position is " << CurrentPosition << "." << endl;
865 // Check whether point is in- or outside
866 FillIt = true;
867 i=0;
868 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
869 // get linked cell list
870 if ((*ListRunner)->TesselStruct == NULL) {
871 *out << Verbose(1) << "ERROR: TesselStruct of " << (*ListRunner) << " is NULL. Didn't we pre-create it?" << endl;
872 FillIt = false;
873 } else
874 FillIt = FillIt && (!(*ListRunner)->TesselStruct->IsInnerPoint(out, CurrentPosition, LCList[i++]));
875 }
876
877 if (FillIt) {
878 // fill in Filler
879 *out << Verbose(2) << "Space at " << CurrentPosition << " is unoccupied by any molecule, filling in." << endl;
880
881 // create molecule random translation vector ...
882 for (int i=0;i<NDIM;i++)
883 FillerTranslations.x[i] = RandomMolDisplacement*(rand()/(RAND_MAX/2.) - 1.);
884 *out << Verbose(3) << "INFO: Translating this filler by " << FillerTranslations << "." << endl;
885
886 // go through all atoms
887 Walker = filler->start;
888 while (Walker->next != filler->end) {
889 Walker = Walker->next;
890 // copy atom ...
891 CopyAtoms[Walker->nr] = new atom(Walker);
892
893 // create atomic random translation vector ...
894 for (int i=0;i<NDIM;i++)
895 AtomTranslations.x[i] = RandomAtomDisplacement*(rand()/(RAND_MAX/2.) - 1.);
896
897 // ... and rotation matrix
898 if (DoRandomRotation) {
899 for (int i=0;i<NDIM;i++) {
900 phi[i] = rand()/(RAND_MAX/(2.*M_PI));
901 }
902
903 Rotations[0] = cos(phi[0]) *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2]));
904 Rotations[3] = sin(phi[0]) *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2]));
905 Rotations[6] = cos(phi[1])*sin(phi[2]) ;
906 Rotations[1] = - sin(phi[0])*cos(phi[1]) ;
907 Rotations[4] = cos(phi[0])*cos(phi[1]) ;
908 Rotations[7] = sin(phi[1]) ;
909 Rotations[3] = - cos(phi[0]) *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2]));
910 Rotations[5] = - sin(phi[0]) *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2]));
911 Rotations[8] = cos(phi[1])*cos(phi[2]) ;
912 }
913
914 // ... and put at new position
915 if (DoRandomRotation)
916 CopyAtoms[Walker->nr]->x.MatrixMultiplication(Rotations);
917 CopyAtoms[Walker->nr]->x.AddVector(&AtomTranslations);
918 CopyAtoms[Walker->nr]->x.AddVector(&FillerTranslations);
919 CopyAtoms[Walker->nr]->x.AddVector(&CurrentPosition);
920
921 // insert into Filling
922
923 // FIXME: gives completely different results if CopyAtoms[..] used instead of Walker, why???
924 *out << Verbose(4) << "Filling atom " << *Walker << ", translated to " << AtomTranslations << ", at final position is " << (CopyAtoms[Walker->nr]->x) << "." << endl;
925 Filling->AddAtom(CopyAtoms[Walker->nr]);
926 }
927
928 // go through all bonds and add as well
929 Binder = filler->first;
930 while(Binder->next != filler->last) {
931 Binder = Binder->next;
932 *out << Verbose(3) << "Adding Bond between " << *CopyAtoms[Binder->leftatom->nr] << " and " << *CopyAtoms[Binder->rightatom->nr]<< "." << endl;
933 Filling->AddBond(CopyAtoms[Binder->leftatom->nr], CopyAtoms[Binder->rightatom->nr], Binder->BondDegree);
934 }
935 } else {
936 // leave empty
937 *out << Verbose(2) << "Space at " << CurrentPosition << " is occupied." << endl;
938 }
939 }
940 *out << Verbose(0) << "End of FillBoxWithMolecule" << endl;
941
942 return Filling;
943};
944
945
946/** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
947 * \param *out output stream for debugging
948 * \param *mol molecule structure with Atom's and Bond's
949 * \param *Tess Tesselation filled with points, lines and triangles on boundary on return
950 * \param *LCList atoms in LinkedCell list
951 * \param RADIUS radius of the virtual sphere
952 * \param *filename filename prefix for output of vertex data
953 */
954void FindNonConvexBorder(ofstream *out, molecule* mol, class LinkedCell *LCList, const double RADIUS, const char *filename = NULL)
955{
956 bool freeLC = false;
957 LineMap::iterator baseline;
958 LineMap::iterator testline;
959 bool OneLoopWithoutSuccessFlag = false; // marks whether we went once through all baselines without finding any without two triangles
960 bool TesselationFailFlag = false;
961
962 *out << Verbose(1) << "Entering search for non convex hull. " << endl;
963 if (mol->TesselStruct == NULL) {
964 *out << Verbose(1) << "Allocating Tesselation struct ..." << endl;
965 mol->TesselStruct = new Tesselation;
966 } else {
967 delete(mol->TesselStruct);
968 *out << Verbose(1) << "Re-Allocating Tesselation struct ..." << endl;
969 mol->TesselStruct = new Tesselation;
970 }
971
972 *out << Verbose(0) << "Begin of FindNonConvexBorder\n";
973
974 // initialise Linked Cell
975 if (LCList == NULL) {
976 LCList = new LinkedCell(mol, 2.*RADIUS);
977 freeLC = true;
978 }
979
980 // 1. get starting triangle
981 mol->TesselStruct->FindStartingTriangle(out, RADIUS, LCList);
982
983 // 2. expand from there
984 baseline = mol->TesselStruct->LinesOnBoundary.begin();
985 baseline++; // skip first line
986 while ((baseline != mol->TesselStruct->LinesOnBoundary.end()) || (OneLoopWithoutSuccessFlag)) {
987 if (baseline->second->triangles.size() == 1) {
988 // 3. find next triangle
989 TesselationFailFlag = mol->TesselStruct->FindNextSuitableTriangle(out, *(baseline->second), *(((baseline->second->triangles.begin()))->second), RADIUS, LCList); //the line is there, so there is a triangle, but only one.
990 OneLoopWithoutSuccessFlag = OneLoopWithoutSuccessFlag || TesselationFailFlag;
991 if (!TesselationFailFlag)
992 cerr << "WARNING: FindNextSuitableTriangle failed." << endl;
993
994 // write temporary envelope
995 if (filename != NULL) {
996 if ((DoSingleStepOutput && ((mol->TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
997 mol->TesselStruct->Output(out, filename, mol);
998 }
999 }
1000 baseline = mol->TesselStruct->LinesOnBoundary.end();
1001 *out << Verbose(2) << "Baseline set to end." << endl;
1002 } else {
1003 //cout << Verbose(1) << "Line " << *baseline->second << " has " << baseline->second->triangles.size() << " triangles adjacent" << endl;
1004 if (baseline->second->triangles.size() != 2)
1005 *out << Verbose(1) << "ERROR: TESSELATION FINISHED WITH INVALID TRIANGLE COUNT!" << endl;
1006 }
1007
1008 if ((baseline == mol->TesselStruct->LinesOnBoundary.end()) && (OneLoopWithoutSuccessFlag)) {
1009 baseline = mol->TesselStruct->LinesOnBoundary.begin(); // restart if we reach end due to newly inserted lines
1010 OneLoopWithoutSuccessFlag = false;
1011 }
1012 baseline++;
1013 }
1014 // check envelope for consistency
1015 CheckListOfBaselines(out, mol->TesselStruct);
1016
1017 // look whether all points are inside of the convex envelope, otherwise add them via degenerated triangles
1018 //mol->TesselStruct->InsertStraddlingPoints(out, mol, LCList);
1019// mol->GoToFirst();
1020// class TesselPoint *Runner = NULL;
1021// while (!mol->IsEnd()) {
1022// Runner = mol->GetPoint();
1023// *out << Verbose(1) << "Checking on " << Runner->Name << " ... " << endl;
1024// if (!mol->TesselStruct->IsInnerPoint(out, Runner, LCList)) {
1025// *out << Verbose(2) << Runner->Name << " is outside of envelope, adding via degenerated triangles." << endl;
1026// mol->TesselStruct->AddBoundaryPointByDegeneratedTriangle(out, Runner, LCList);
1027// } else {
1028// *out << Verbose(2) << Runner->Name << " is inside of or on envelope." << endl;
1029// }
1030// mol->GoToNext();
1031// }
1032
1033 // Purges surplus triangles.
1034 mol->TesselStruct->RemoveDegeneratedTriangles();
1035
1036 // check envelope for consistency
1037 CheckListOfBaselines(out, mol->TesselStruct);
1038
1039 // write final envelope
1040 CalculateConcavityPerBoundaryPoint(out, mol->TesselStruct);
1041 StoreTrianglesinFile(out, mol, filename, "");
1042
1043 if (freeLC)
1044 delete(LCList);
1045 *out << Verbose(0) << "End of FindNonConvexBorder\n";
1046};
1047
1048
1049/** Finds a hole of sufficient size in \a *mols to embed \a *srcmol into it.
1050 * \param *out output stream for debugging
1051 * \param *mols molecules in the domain to embed in between
1052 * \param *srcmol embedding molecule
1053 * \return *Vector new center of \a *srcmol for embedding relative to \a this
1054 */
1055Vector* FindEmbeddingHole(ofstream *out, MoleculeListClass *mols, molecule *srcmol)
1056{
1057 Vector *Center = new Vector;
1058 Center->Zero();
1059 // calculate volume/shape of \a *srcmol
1060
1061 // find embedding holes
1062
1063 // if more than one, let user choose
1064
1065 // return embedding center
1066 return Center;
1067};
1068
Note: See TracBrowser for help on using the repository browser.