source: src/boundary.cpp@ 70ff32

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 70ff32 was f66195, checked in by Frederik Heber <heber@…>, 15 years ago

forward declarations used to untangle interdependet classes.

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