source: src/boundary.cpp@ 72e7fa

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 72e7fa was 0a4f7f, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Made data internal data-structure of vector class private

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