source: src/boundary.cpp@ 57066a

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 57066a was 57066a, checked in by Frederik Heber <heber@…>, 16 years ago

Various fixes and attempt to get convex hull working.

Moved tesselation writing to tesselation.cpp

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