source: src/Tesselation/boundary.cpp@ 52575c

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 52575c was ce7bfd, checked in by Frederik Heber <heber@…>, 13 years ago

VERBOSE: Subsequent change in verbosity levels of many tesselation functions after Info removal.

  • Property mode set to 100644
File size: 67.4 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
5 * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
6 */
7
8/** \file boundary.cpp
9 *
10 * Implementations and super-function for envelopes
11 */
12
13// include config.h
14#ifdef HAVE_CONFIG_H
15#include <config.h>
16#endif
17
18#include "CodePatterns/MemDebug.hpp"
19
20#include "Atom/atom.hpp"
21#include "Bond/bond.hpp"
22#include "boundary.hpp"
23#include "BoundaryLineSet.hpp"
24#include "BoundaryPointSet.hpp"
25#include "BoundaryTriangleSet.hpp"
26#include "Box.hpp"
27#include "CandidateForTesselation.hpp"
28#include "CodePatterns/Info.hpp"
29#include "CodePatterns/Log.hpp"
30#include "CodePatterns/Verbose.hpp"
31#include "config.hpp"
32#include "Element/element.hpp"
33#include "LinearAlgebra/Plane.hpp"
34#include "LinearAlgebra/RealSpaceMatrix.hpp"
35#include "LinkedCell/linkedcell.hpp"
36#include "LinkedCell/PointCloudAdaptor.hpp"
37#include "molecule.hpp"
38#include "MoleculeListClass.hpp"
39#include "RandomNumbers/RandomNumberGeneratorFactory.hpp"
40#include "RandomNumbers/RandomNumberGenerator.hpp"
41#include "tesselation.hpp"
42#include "tesselationhelpers.hpp"
43#include "World.hpp"
44
45#include <iostream>
46#include <iomanip>
47
48#include<gsl/gsl_poly.h>
49#include<time.h>
50
51// ========================================== F U N C T I O N S =================================
52
53
54/** Determines greatest diameters of a cluster defined by its convex envelope.
55 * Looks at lines parallel to one axis and where they intersect on the projected planes
56 * \param *out output stream for debugging
57 * \param *BoundaryPoints NDIM set of boundary points defining the convex envelope on each projected plane
58 * \param *mol molecule structure representing the cluster
59 * \param *&TesselStruct Tesselation structure with triangles
60 * \param IsAngstroem whether we have angstroem or atomic units
61 * \return NDIM array of the diameters
62 */
63double *GetDiametersOfCluster(const Boundaries *BoundaryPtr, const molecule *mol, Tesselation *&TesselStruct, const bool IsAngstroem)
64{
65 //Info FunctionInfo(__func__);
66 // get points on boundary of NULL was given as parameter
67 bool BoundaryFreeFlag = false;
68 double OldComponent = 0.;
69 double tmp = 0.;
70 double w1 = 0.;
71 double w2 = 0.;
72 Vector DistanceVector;
73 Vector OtherVector;
74 int component = 0;
75 int Othercomponent = 0;
76 Boundaries::const_iterator Neighbour;
77 Boundaries::const_iterator OtherNeighbour;
78 double *GreatestDiameter = new double[NDIM];
79
80 const Boundaries *BoundaryPoints;
81 if (BoundaryPtr == NULL) {
82 BoundaryFreeFlag = true;
83 BoundaryPoints = GetBoundaryPoints(mol, TesselStruct);
84 } else {
85 BoundaryPoints = BoundaryPtr;
86 LOG(0, "Using given boundary points set.");
87 }
88 // determine biggest "diameter" of cluster for each axis
89 for (int i = 0; i < NDIM; i++)
90 GreatestDiameter[i] = 0.;
91 for (int axis = 0; axis < NDIM; axis++)
92 { // regard each projected plane
93 //LOG(1, "Current axis is " << axis << ".");
94 for (int j = 0; j < 2; j++)
95 { // and for both axis on the current plane
96 component = (axis + j + 1) % NDIM;
97 Othercomponent = (axis + 1 + ((j + 1) & 1)) % NDIM;
98 //LOG(1, "Current component is " << component << ", Othercomponent is " << Othercomponent << ".");
99 for (Boundaries::const_iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
100 //LOG(1, "Current runner is " << *(runner->second.second) << ".");
101 // seek for the neighbours pair where the Othercomponent sign flips
102 Neighbour = runner;
103 Neighbour++;
104 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
105 Neighbour = BoundaryPoints[axis].begin();
106 DistanceVector = (runner->second.second->getPosition()) - (Neighbour->second.second->getPosition());
107 do { // seek for neighbour pair where it flips
108 OldComponent = DistanceVector[Othercomponent];
109 Neighbour++;
110 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
111 Neighbour = BoundaryPoints[axis].begin();
112 DistanceVector = (runner->second.second->getPosition()) - (Neighbour->second.second->getPosition());
113 //LOG(2, "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << ".");
114 } while ((runner != Neighbour) && (fabs(OldComponent / fabs(
115 OldComponent) - DistanceVector[Othercomponent] / fabs(
116 DistanceVector[Othercomponent])) < MYEPSILON)); // as long as sign does not flip
117 if (runner != Neighbour) {
118 OtherNeighbour = Neighbour;
119 if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around
120 OtherNeighbour = BoundaryPoints[axis].end();
121 OtherNeighbour--;
122 //LOG(1, "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << ".");
123 // now we have found the pair: Neighbour and OtherNeighbour
124 OtherVector = (runner->second.second->getPosition()) - (OtherNeighbour->second.second->getPosition());
125 //LOG(1, "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << ".");
126 //LOG(1, "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << ".");
127 // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour
128 w1 = fabs(OtherVector[Othercomponent]);
129 w2 = fabs(DistanceVector[Othercomponent]);
130 tmp = fabs((w1 * DistanceVector[component] + w2
131 * OtherVector[component]) / (w1 + w2));
132 // mark if it has greater diameter
133 //LOG(1, "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << ".");
134 GreatestDiameter[component] = (GreatestDiameter[component]
135 > tmp) ? GreatestDiameter[component] : tmp;
136 } //else
137 //LOG(1, "Saw no sign flip, probably top or bottom node.");
138 }
139 }
140 }
141 LOG(0, "RESULT: The biggest diameters are "
142 << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and "
143 << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom"
144 : "atomiclength") << ".");
145
146 // free reference lists
147 if (BoundaryFreeFlag)
148 delete[] (BoundaryPoints);
149
150 return GreatestDiameter;
151}
152;
153
154
155/** Determines the boundary points of a cluster.
156 * Does a projection per axis onto the orthogonal plane, transforms into spherical coordinates, sorts them by the angle
157 * and looks at triples: if the middle has less a distance than the allowed maximum height of the triangle formed by the plane's
158 * center and first and last point in the triple, it is thrown out.
159 * \param *out output stream for debugging
160 * \param *mol molecule structure representing the cluster
161 * \param *&TesselStruct pointer to Tesselation structure
162 */
163Boundaries *GetBoundaryPoints(const molecule *mol, Tesselation *&TesselStruct)
164{
165 //Info FunctionInfo(__func__);
166 PointMap PointsOnBoundary;
167 LineMap LinesOnBoundary;
168 TriangleMap TrianglesOnBoundary;
169 Vector *MolCenter = mol->DetermineCenterOfAll();
170 Vector helper;
171 BoundariesTestPair BoundaryTestPair;
172 Vector AxisVector;
173 Vector AngleReferenceVector;
174 Vector AngleReferenceNormalVector;
175 Vector ProjectedVector;
176 Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, Nr)
177 double angle = 0.;
178
179 // 3a. Go through every axis
180 for (int axis = 0; axis < NDIM; axis++) {
181 AxisVector.Zero();
182 AngleReferenceVector.Zero();
183 AngleReferenceNormalVector.Zero();
184 AxisVector[axis] = 1.;
185 AngleReferenceVector[(axis + 1) % NDIM] = 1.;
186 AngleReferenceNormalVector[(axis + 2) % NDIM] = 1.;
187
188 LOG(1, "Axisvector is " << AxisVector << " and AngleReferenceVector is " << AngleReferenceVector << ", and AngleReferenceNormalVector is " << AngleReferenceNormalVector << ".");
189
190 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
191 // Boundaries stores non-const TesselPoint ref, hence we need iterator here
192 for (molecule::iterator iter = mol->begin(); iter != mol->end(); ++iter) {
193 ProjectedVector = (*iter)->getPosition() - (*MolCenter);
194 ProjectedVector.ProjectOntoPlane(AxisVector);
195
196 // correct for negative side
197 const double radius = ProjectedVector.NormSquared();
198 if (fabs(radius) > MYEPSILON)
199 angle = ProjectedVector.Angle(AngleReferenceVector);
200 else
201 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
202
203 //LOG(1, "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << ".");
204 if (ProjectedVector.ScalarProduct(AngleReferenceNormalVector) > 0) {
205 angle = 2. * M_PI - angle;
206 }
207 LOG(1, "Inserting " << **iter << ": (r, alpha) = (" << radius << "," << angle << "): " << ProjectedVector);
208 BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle, TesselPointDistancePair (radius, (*iter))));
209 if (!BoundaryTestPair.second) { // same point exists, check first r, then distance of original vectors to center of gravity
210 LOG(2, "Encountered two vectors whose projection onto axis " << axis << " is equal: ");
211 LOG(2, "Present vector: " << *BoundaryTestPair.first->second.second);
212 LOG(2, "New vector: " << **iter);
213 const double ProjectedVectorNorm = ProjectedVector.NormSquared();
214 if ((ProjectedVectorNorm - BoundaryTestPair.first->second.first) > MYEPSILON) {
215 BoundaryTestPair.first->second.first = ProjectedVectorNorm;
216 BoundaryTestPair.first->second.second = (*iter);
217 LOG(2, "Keeping new vector due to larger projected distance " << ProjectedVectorNorm << ".");
218 } else if (fabs(ProjectedVectorNorm - BoundaryTestPair.first->second.first) < MYEPSILON) {
219 helper = (*iter)->getPosition() - (*MolCenter);
220 const double oldhelperNorm = helper.NormSquared();
221 helper = BoundaryTestPair.first->second.second->getPosition() - (*MolCenter);
222 if (helper.NormSquared() < oldhelperNorm) {
223 BoundaryTestPair.first->second.second = (*iter);
224 LOG(2, "Keeping new vector due to larger distance to molecule center " << helper.NormSquared() << ".");
225 } else {
226 LOG(2, "Keeping present vector due to larger distance to molecule center " << oldhelperNorm << ".");
227 }
228 } else {
229 LOG(2, "Keeping present vector due to larger projected distance " << ProjectedVectorNorm << ".");
230 }
231 }
232 }
233 // printing all inserted for debugging
234 // {
235 // std::stringstream output;
236 // output << "Printing list of candidates for axis " << axis << " which we have inserted so far: ";
237 // int i=0;
238 // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
239 // if (runner != BoundaryPoints[axis].begin())
240 // output << ", " << i << ": " << *runner->second.second;
241 // else
242 // output << i << ": " << *runner->second.second;
243 // i++;
244 // }
245 // LOG(1, output.str());
246 // }
247 // 3c. throw out points whose distance is less than the mean of left and right neighbours
248 bool flag = false;
249 LOG(1, "Looking for candidates to kick out by convex condition ... ");
250 do { // do as long as we still throw one out per round
251 flag = false;
252 Boundaries::iterator left = BoundaryPoints[axis].begin();
253 Boundaries::iterator right = BoundaryPoints[axis].begin();
254 Boundaries::iterator runner = BoundaryPoints[axis].begin();
255 bool LoopOnceDone = false;
256 while (!LoopOnceDone) {
257 runner = right;
258 right++;
259 // set neighbours correctly
260 if (runner == BoundaryPoints[axis].begin()) {
261 left = BoundaryPoints[axis].end();
262 } else {
263 left = runner;
264 }
265 left--;
266 if (right == BoundaryPoints[axis].end()) {
267 right = BoundaryPoints[axis].begin();
268 LoopOnceDone = true;
269 }
270 // check distance
271
272 // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)
273 {
274 Vector SideA, SideB, SideC, SideH;
275 SideA = left->second.second->getPosition() - (*MolCenter);
276 SideA.ProjectOntoPlane(AxisVector);
277 // LOG(1, "SideA: " << SideA);
278
279 SideB = right->second.second->getPosition() -(*MolCenter);
280 SideB.ProjectOntoPlane(AxisVector);
281 // LOG(1, "SideB: " << SideB);
282
283 SideC = left->second.second->getPosition() - right->second.second->getPosition();
284 SideC.ProjectOntoPlane(AxisVector);
285 // LOG(1, "SideC: " << SideC);
286
287 SideH = runner->second.second->getPosition() -(*MolCenter);
288 SideH.ProjectOntoPlane(AxisVector);
289 // LOG(1, "SideH: " << SideH);
290
291 // calculate each length
292 const double a = SideA.Norm();
293 //const double b = SideB.Norm();
294 //const double c = SideC.Norm();
295 const double h = SideH.Norm();
296 // calculate the angles
297 const double alpha = SideA.Angle(SideH);
298 const double beta = SideA.Angle(SideC);
299 const double gamma = SideB.Angle(SideH);
300 const double delta = SideC.Angle(SideH);
301 const double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.);
302 //LOG(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 << ".");
303 LOG(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 << ".");
304 if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance)) < MYEPSILON) && ((h - MinDistance)) < -MYEPSILON) {
305 // throw out point
306 LOG(1, "Throwing out " << *runner->second.second << ".");
307 BoundaryPoints[axis].erase(runner);
308 runner = right;
309 flag = true;
310 }
311 }
312 }
313 } while (flag);
314 }
315 delete(MolCenter);
316 return BoundaryPoints;
317};
318
319/** Tesselates the convex boundary by finding all boundary points.
320 * \param *out output stream for debugging
321 * \param *mol molecule structure with Atom's and Bond's.
322 * \param *BoundaryPts set of boundary points to use or NULL
323 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
324 * \param *LCList atoms in LinkedCell_deprecated list
325 * \param *filename filename prefix for output of vertex data
326 * \return *TesselStruct is filled with convex boundary and tesselation is stored under \a *filename.
327 */
328void FindConvexBorder(const molecule* mol, Boundaries *BoundaryPts, Tesselation *&TesselStruct, const LinkedCell_deprecated *LCList, const char *filename)
329{
330 //Info FunctionInfo(__func__);
331 bool BoundaryFreeFlag = false;
332 Boundaries *BoundaryPoints = NULL;
333
334 if (TesselStruct != NULL) // free if allocated
335 delete(TesselStruct);
336 TesselStruct = new class Tesselation;
337
338 // 1. Find all points on the boundary
339 if (BoundaryPts == NULL) {
340 BoundaryFreeFlag = true;
341 BoundaryPoints = GetBoundaryPoints(mol, TesselStruct);
342 } else {
343 BoundaryPoints = BoundaryPts;
344 LOG(0, "Using given boundary points set.");
345 }
346
347// printing all inserted for debugging
348 if (DoLog(1)) {
349 for (int axis=0; axis < NDIM; axis++) {
350 std::stringstream output;
351 output << "Printing list of candidates for axis " << axis << " which we have inserted so far: ";
352 int i=0;
353 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
354 if (runner != BoundaryPoints[axis].begin())
355 output << ", " << i << ": " << *runner->second.second;
356 else
357 output << i << ": " << *runner->second.second;
358 i++;
359 }
360 LOG(1, output.str());
361 }
362 }
363
364 // 2. fill the boundary point list
365 for (int axis = 0; axis < NDIM; axis++)
366 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++)
367 if (!TesselStruct->AddBoundaryPoint(runner->second.second, 0))
368 LOG(2, "Point " << *(runner->second.second) << " is already present.");
369
370 LOG(0, "I found " << TesselStruct->PointsOnBoundaryCount << " points on the convex boundary.");
371 // now we have the whole set of edge points in the BoundaryList
372
373 // listing for debugging
374 //if (DoLog(1)) {
375 // std::stringstream output;
376 // output << "Listing PointsOnBoundary:";
377 // for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
378 // output << " " << *runner->second;
379 // }
380 // LOG(1, output.str());
381 //}
382
383 // 3a. guess starting triangle
384 TesselStruct->GuessStartingTriangle();
385
386 // 3b. go through all lines, that are not yet part of two triangles (only of one so far)
387 PointCloudAdaptor< molecule > cloud(const_cast<molecule *>(mol), mol->name);
388 TesselStruct->TesselateOnBoundary(cloud);
389
390 // 3c. check whether all atoms lay inside the boundary, if not, add to boundary points, segment triangle into three with the new point
391 if (!TesselStruct->InsertStraddlingPoints(cloud, LCList))
392 ELOG(1, "Insertion of straddling points failed!");
393
394 LOG(0, "I created " << TesselStruct->TrianglesOnBoundary.size() << " intermediate triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points.");
395
396 // 4. Store triangles in tecplot file
397 StoreTrianglesinFile(mol, TesselStruct, filename, "_intermed");
398
399 // 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
400 bool AllConvex = true;
401 class BoundaryLineSet *line = NULL;
402 do {
403 AllConvex = true;
404 for (LineMap::iterator LineRunner = TesselStruct->LinesOnBoundary.begin(); LineRunner != TesselStruct->LinesOnBoundary.end(); LineRunner++) {
405 line = LineRunner->second;
406 LOG(1, "INFO: Current line is " << *line << ".");
407 if (!line->CheckConvexityCriterion()) {
408 LOG(1, "... line " << *line << " is concave, flipping it.");
409
410 // flip the line
411 if (TesselStruct->PickFarthestofTwoBaselines(line) == 0.)
412 ELOG(1, "Correction of concave baselines failed!");
413 else {
414 TesselStruct->FlipBaseline(line);
415 LOG(1, "INFO: Correction of concave baselines worked.");
416 LineRunner = TesselStruct->LinesOnBoundary.begin(); // LineRunner may have been erase if line was deleted from LinesOnBoundary
417 }
418 }
419 }
420 } while (!AllConvex);
421
422 // 3e. we need another correction here, for TesselPoints that are below the surface (i.e. have an odd number of concave triangles surrounding it)
423// if (!TesselStruct->CorrectConcaveTesselPoints(out))
424// ELOG(1, "Correction of concave tesselpoints failed!");
425
426 LOG(0, "I created " << TesselStruct->TrianglesOnBoundary.size() << " triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points.");
427
428 // 4. Store triangles in tecplot file
429 StoreTrianglesinFile(mol, TesselStruct, filename, "");
430
431 // free reference lists
432 if (BoundaryFreeFlag)
433 delete[] (BoundaryPoints);
434};
435
436/** For testing removes one boundary point after another to check for leaks.
437 * \param *out output stream for debugging
438 * \param *TesselStruct Tesselation containing envelope with boundary points
439 * \param *mol molecule
440 * \param *filename name of file
441 * \return true - all removed, false - something went wrong
442 */
443bool RemoveAllBoundaryPoints(class Tesselation *&TesselStruct, const molecule * const mol, const char * const filename)
444{
445 //Info FunctionInfo(__func__);
446 int i=0;
447 char number[MAXSTRINGSIZE];
448
449 if ((TesselStruct == NULL) || (TesselStruct->PointsOnBoundary.empty())) {
450 ELOG(1, "TesselStruct is empty.");
451 return false;
452 }
453
454 PointMap::iterator PointRunner;
455 while (!TesselStruct->PointsOnBoundary.empty()) {
456 if (DoLog(1)) {
457 std::stringstream output;
458 output << "Remaining points are: ";
459 for (PointMap::iterator PointSprinter = TesselStruct->PointsOnBoundary.begin(); PointSprinter != TesselStruct->PointsOnBoundary.end(); PointSprinter++)
460 output << *(PointSprinter->second) << "\t";
461 LOG(1, output.str());
462 }
463
464 PointRunner = TesselStruct->PointsOnBoundary.begin();
465 // remove point
466 TesselStruct->RemovePointFromTesselatedSurface(PointRunner->second);
467
468 // store envelope
469 sprintf(number, "-%04d", i++);
470 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, number);
471 }
472
473 return true;
474};
475
476/** Creates a convex envelope from a given non-convex one.
477 * -# First step, remove concave spots, i.e. singular "dents"
478 * -# We go through all PointsOnBoundary.
479 * -# We CheckConvexityCriterion() for all its lines.
480 * -# If all its lines are concave, it cannot be on the convex envelope.
481 * -# Hence, we remove it and re-create all its triangles from its getCircleOfConnectedPoints()
482 * -# We calculate the additional volume.
483 * -# We go over all lines until none yields a concavity anymore.
484 * -# Second step, remove concave lines, i.e. line-shape "dents"
485 * -# We go through all LinesOnBoundary
486 * -# We CheckConvexityCriterion()
487 * -# If it returns concave, we flip the line in this quadrupel of points (abusing the degeneracy of the tesselation)
488 * -# We CheckConvexityCriterion(),
489 * -# if it's concave, we continue
490 * -# if not, we mark an error and stop
491 * Note: This routine - for free - calculates the difference in volume between convex and
492 * non-convex envelope, as the former is easy to calculate - Tesselation::getVolumeOfConvexEnvelope() - it
493 * can be used to compute volumes of arbitrary shapes.
494 * \param *out output stream for debugging
495 * \param *TesselStruct non-convex envelope, is changed in return!
496 * \param *mol molecule
497 * \param *filename name of file
498 * \return volume difference between the non- and the created convex envelope
499 */
500double ConvexizeNonconvexEnvelope(class Tesselation *&TesselStruct, const molecule * const mol, const char * const filename)
501{
502 //Info FunctionInfo(__func__);
503 double volume = 0;
504 class BoundaryPointSet *point = NULL;
505 class BoundaryLineSet *line = NULL;
506 bool Concavity = false;
507 char dummy[MAXSTRINGSIZE];
508 PointMap::iterator PointRunner;
509 PointMap::iterator PointAdvance;
510 LineMap::iterator LineRunner;
511 LineMap::iterator LineAdvance;
512 TriangleMap::iterator TriangleRunner;
513 TriangleMap::iterator TriangleAdvance;
514 int run = 0;
515
516 // check whether there is something to work on
517 if (TesselStruct == NULL) {
518 ELOG(1, "TesselStruct is empty!");
519 return volume;
520 }
521
522 // First step: RemovePointFromTesselatedSurface
523 do {
524 Concavity = false;
525 sprintf(dummy, "-first-%d", run);
526 //CalculateConcavityPerBoundaryPoint(TesselStruct);
527 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
528
529 PointRunner = TesselStruct->PointsOnBoundary.begin();
530 PointAdvance = PointRunner; // we need an advanced point, as the PointRunner might get removed
531 while (PointRunner != TesselStruct->PointsOnBoundary.end()) {
532 PointAdvance++;
533 point = PointRunner->second;
534 LOG(1, "INFO: Current point is " << *point << ".");
535 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++) {
536 line = LineRunner->second;
537 LOG(1, "INFO: Current line of point " << *point << " is " << *line << ".");
538 if (!line->CheckConvexityCriterion()) {
539 // remove the point if needed
540 LOG(1, "... point " << *point << " cannot be on convex envelope.");
541 volume += TesselStruct->RemovePointFromTesselatedSurface(point);
542 sprintf(dummy, "-first-%d", ++run);
543 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
544 Concavity = true;
545 break;
546 }
547 }
548 PointRunner = PointAdvance;
549 }
550
551 sprintf(dummy, "-second-%d", run);
552 //CalculateConcavityPerBoundaryPoint(TesselStruct);
553 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
554
555 // second step: PickFarthestofTwoBaselines
556 LineRunner = TesselStruct->LinesOnBoundary.begin();
557 LineAdvance = LineRunner; // we need an advanced line, as the LineRunner might get removed
558 while (LineRunner != TesselStruct->LinesOnBoundary.end()) {
559 LineAdvance++;
560 line = LineRunner->second;
561 LOG(1, "INFO: Picking farthest baseline for line is " << *line << ".");
562 // take highest of both lines
563 if (TesselStruct->IsConvexRectangle(line) == NULL) {
564 const double tmp = TesselStruct->PickFarthestofTwoBaselines(line);
565 volume += tmp;
566 if (tmp != 0.) {
567 TesselStruct->FlipBaseline(line);
568 Concavity = true;
569 }
570 }
571 LineRunner = LineAdvance;
572 }
573 run++;
574 } while (Concavity);
575 //CalculateConcavityPerBoundaryPoint(TesselStruct);
576 //StoreTrianglesinFile(mol, filename, "-third");
577
578 // third step: IsConvexRectangle
579// LineRunner = TesselStruct->LinesOnBoundary.begin();
580// LineAdvance = LineRunner; // we need an advanced line, as the LineRunner might get removed
581// while (LineRunner != TesselStruct->LinesOnBoundary.end()) {
582// LineAdvance++;
583// line = LineRunner->second;
584// LOG(1, "INFO: Current line is " << *line << ".");
585// //if (LineAdvance != TesselStruct->LinesOnBoundary.end())
586// //LOG(1, "INFO: Next line will be " << *(LineAdvance->second) << ".");
587// if (!line->CheckConvexityCriterion(out)) {
588// LOG(1, "INFO: ... line " << *line << " is concave, flipping it.");
589//
590// // take highest of both lines
591// point = TesselStruct->IsConvexRectangle(line);
592// if (point != NULL)
593// volume += TesselStruct->RemovePointFromTesselatedSurface(point);
594// }
595// LineRunner = LineAdvance;
596// }
597
598 CalculateConcavityPerBoundaryPoint(TesselStruct);
599 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, "");
600
601 // end
602 LOG(0, "Volume is " << volume << ".");
603 return volume;
604};
605
606
607/** Stores triangles to file.
608 * \param *out output stream for debugging
609 * \param *mol molecule with atoms and bonds
610 * \param *TesselStruct Tesselation with boundary triangles
611 * \param *filename prefix of filename
612 * \param *extraSuffix intermediate suffix
613 */
614void StoreTrianglesinFile(const molecule * const mol, const Tesselation * const TesselStruct, const char *filename, const char *extraSuffix)
615{
616 //Info FunctionInfo(__func__);
617 PointCloudAdaptor< molecule > cloud(const_cast<molecule *>(mol), mol->name);
618 // 4. Store triangles in tecplot file
619 if (filename != NULL) {
620 if (DoTecplotOutput) {
621 string OutputName(filename);
622 OutputName.append(extraSuffix);
623 OutputName.append(TecplotSuffix);
624 ofstream *tecplot = new ofstream(OutputName.c_str());
625 WriteTecplotFile(tecplot, TesselStruct, cloud, -1);
626 tecplot->close();
627 delete(tecplot);
628 }
629 if (DoRaster3DOutput) {
630 string OutputName(filename);
631 OutputName.append(extraSuffix);
632 OutputName.append(Raster3DSuffix);
633 ofstream *rasterplot = new ofstream(OutputName.c_str());
634 WriteRaster3dFile(rasterplot, TesselStruct, cloud);
635 rasterplot->close();
636 delete(rasterplot);
637 }
638 }
639};
640
641/** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
642 * We get cluster volume by Tesselation::getVolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
643 * TODO: Here, we need a VolumeOfGeneralEnvelope (i.e. non-convex one)
644 * \param *out output stream for debugging
645 * \param *configuration needed for path to store convex envelope file
646 * \param *mol molecule structure representing the cluster
647 * \param *&TesselStruct Tesselation structure with triangles on return
648 * \param ClusterVolume guesstimated cluster volume, if equal 0 we used Tesselation::getVolumeOfConvexEnvelope() instead.
649 * \param celldensity desired average density in final cell
650 */
651void PrepareClustersinWater(config *configuration, molecule *mol, double ClusterVolume, double celldensity)
652{
653 //Info FunctionInfo(__func__);
654 bool IsAngstroem = true;
655 double *GreatestDiameter = NULL;
656 Boundaries *BoundaryPoints = NULL;
657 class Tesselation *TesselStruct = NULL;
658 Vector BoxLengths;
659 int repetition[NDIM] = { 1, 1, 1 };
660 int TotalNoClusters = 1;
661 double totalmass = 0.;
662 double clustervolume = 0.;
663 double cellvolume = 0.;
664
665 // transform to PAS by Action
666 Vector MainAxis(0.,0.,1.);
667 mol->RotateToPrincipalAxisSystem(MainAxis);
668
669 IsAngstroem = configuration->GetIsAngstroem();
670 BoundaryPoints = GetBoundaryPoints(mol, TesselStruct);
671 GreatestDiameter = GetDiametersOfCluster(BoundaryPoints, mol, TesselStruct, IsAngstroem);
672 PointCloudAdaptor< molecule > cloud(mol, mol->name);
673 LinkedCell_deprecated *LCList = new LinkedCell_deprecated(cloud, 10.);
674 FindConvexBorder(mol, BoundaryPoints, TesselStruct, (const LinkedCell_deprecated *&)LCList, NULL);
675 delete (LCList);
676 delete[] BoundaryPoints;
677
678
679 // some preparations beforehand
680 if (ClusterVolume == 0)
681 clustervolume = TesselStruct->getVolumeOfConvexEnvelope(configuration->GetIsAngstroem());
682 else
683 clustervolume = ClusterVolume;
684
685 delete TesselStruct;
686
687 for (int i = 0; i < NDIM; i++)
688 TotalNoClusters *= repetition[i];
689
690 // sum up the atomic masses
691 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
692 totalmass += (*iter)->getType()->getMass();
693 }
694 LOG(0, "RESULT: The summed mass is " << setprecision(10) << totalmass << " atomicmassunit.");
695 LOG(0, "RESULT: The average density is " << setprecision(10) << totalmass / clustervolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3.");
696
697 // solve cubic polynomial
698 LOG(1, "Solving equidistant suspension in water problem ...");
699 if (IsAngstroem)
700 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_A - (totalmass / clustervolume)) / (celldensity - 1);
701 else
702 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_a0 - (totalmass / clustervolume)) / (celldensity - 1);
703 LOG(1, "Cellvolume needed for a density of " << celldensity << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3.");
704
705 double minimumvolume = TotalNoClusters * (GreatestDiameter[0] * GreatestDiameter[1] * GreatestDiameter[2]);
706 LOG(1, "Minimum volume of the convex envelope contained in a rectangular box is " << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3.");
707 if (minimumvolume > cellvolume) {
708 ELOG(1, "the containing box already has a greater volume than the envisaged cell volume!");
709 LOG(0, "Setting Box dimensions to minimum possible, the greatest diameters.");
710 for (int i = 0; i < NDIM; i++)
711 BoxLengths[i] = GreatestDiameter[i];
712 mol->CenterEdge(&BoxLengths);
713 } else {
714 BoxLengths[0] = (repetition[0] * GreatestDiameter[0] + repetition[1] * GreatestDiameter[1] + repetition[2] * GreatestDiameter[2]);
715 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]);
716 BoxLengths[2] = minimumvolume - cellvolume;
717 double x0 = 0.;
718 double x1 = 0.;
719 double x2 = 0.;
720 if (gsl_poly_solve_cubic(BoxLengths[0], BoxLengths[1], BoxLengths[2], &x0, &x1, &x2) == 1) // either 1 or 3 on return
721 LOG(0, "RESULT: The resulting spacing is: " << x0 << " .");
722 else {
723 LOG(0, "RESULT: The resulting spacings are: " << x0 << " and " << x1 << " and " << x2 << " .");
724 x0 = x2; // sorted in ascending order
725 }
726
727 cellvolume = 1.;
728 for (int i = 0; i < NDIM; i++) {
729 BoxLengths[i] = repetition[i] * (x0 + GreatestDiameter[i]);
730 cellvolume *= BoxLengths[i];
731 }
732
733 // set new box dimensions
734 LOG(0, "Translating to box with these boundaries.");
735 mol->SetBoxDimension(&BoxLengths);
736 mol->CenterInBox();
737 }
738 delete GreatestDiameter;
739 // update Box of atoms by boundary
740 mol->SetBoxDimension(&BoxLengths);
741 LOG(0, "RESULT: The resulting cell dimensions are: " << BoxLengths[0] << " and " << BoxLengths[1] << " and " << BoxLengths[2] << " with total volume of " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3.");
742};
743
744
745/** Fills the empty space around other molecules' surface of the simulation box with a filler.
746 * \param *out output stream for debugging
747 * \param *List list of molecules already present in box
748 * \param *TesselStruct contains tesselated surface
749 * \param *filler molecule which the box is to be filled with
750 * \param configuration contains box dimensions
751 * \param MaxDistance fills in molecules only up to this distance (set to -1 if whole of the domain)
752 * \param distance[NDIM] distance between filling molecules in each direction
753 * \param boundary length of boundary zone between molecule and filling mollecules
754 * \param epsilon distance to surface which is not filled
755 * \param RandAtomDisplacement maximum distance for random displacement per atom
756 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
757 * \param DoRandomRotation true - do random rotiations, false - don't
758 */
759void FillBoxWithMolecule(MoleculeListClass *List, molecule *filler, config &configuration, const double MaxDistance, const double distance[NDIM], const double boundary, const double RandomAtomDisplacement, const double RandomMolDisplacement, const bool DoRandomRotation)
760{
761 //Info FunctionInfo(__func__);
762 molecule *Filling = World::getInstance().createMolecule();
763 Vector CurrentPosition;
764 int N[NDIM];
765 int n[NDIM];
766 const RealSpaceMatrix &M = World::getInstance().getDomain().getM();
767 RealSpaceMatrix Rotations;
768 const RealSpaceMatrix &MInverse = World::getInstance().getDomain().getMinv();
769 Vector AtomTranslations;
770 Vector FillerTranslations;
771 Vector FillerDistance;
772 Vector Inserter;
773 double FillIt = false;
774 bond *Binder = NULL;
775 double phi[NDIM];
776 map<molecule *, Tesselation *> TesselStruct;
777 map<molecule *, LinkedCell_deprecated *> LCList;
778
779 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++)
780 if ((*ListRunner)->getAtomCount() > 0) {
781 LOG(1, "Pre-creating linked cell lists for molecule " << *ListRunner << ".");
782 PointCloudAdaptor< molecule > cloud(*ListRunner, (*ListRunner)->name);
783 LCList[(*ListRunner)] = new LinkedCell_deprecated(cloud, 10.); // get linked cell list
784 LOG(1, "Pre-creating tesselation for molecule " << *ListRunner << ".");
785 TesselStruct[(*ListRunner)] = NULL;
786 FindNonConvexBorder((*ListRunner), TesselStruct[(*ListRunner)], (const LinkedCell_deprecated *&)LCList[(*ListRunner)], 5., NULL);
787 }
788
789 // Center filler at origin
790 filler->CenterEdge(&Inserter);
791 const int FillerCount = filler->getAtomCount();
792 LOG(2, "INFO: Filler molecule has the following bonds:");
793 for(molecule::iterator AtomRunner = filler->begin(); AtomRunner != filler->end(); ++AtomRunner) {
794 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
795 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
796 BondRunner != ListOfBonds.end();
797 ++BondRunner) {
798 if ((*BondRunner)->leftatom == *AtomRunner)
799 LOG(2, " " << *(*BondRunner));
800 }
801 }
802
803 atom * CopyAtoms[FillerCount];
804
805 // calculate filler grid in [0,1]^3
806 FillerDistance = MInverse * Vector(distance[0], distance[1], distance[2]);
807 for(int i=0;i<NDIM;i++)
808 N[i] = (int) ceil(1./FillerDistance[i]);
809 LOG(1, "INFO: Grid steps are " << N[0] << ", " << N[1] << ", " << N[2] << ".");
810
811 // initialize seed of random number generator to current time
812 RandomNumberGenerator &random = RandomNumberGeneratorFactory::getInstance().makeRandomNumberGenerator();
813 const double rng_min = random.min();
814 const double rng_max = random.max();
815 //srand ( time(NULL) );
816
817 // go over [0,1]^3 filler grid
818 for (n[0] = 0; n[0] < N[0]; n[0]++)
819 for (n[1] = 0; n[1] < N[1]; n[1]++)
820 for (n[2] = 0; n[2] < N[2]; n[2]++) {
821 // calculate position of current grid vector in untransformed box
822 CurrentPosition = M * Vector((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
823 // create molecule random translation vector ...
824 for (int i=0;i<NDIM;i++)
825 FillerTranslations[i] = RandomMolDisplacement*(random()/((rng_max-rng_min)/2.) - 1.);
826 LOG(2, "INFO: Current Position is " << CurrentPosition << "+" << FillerTranslations << ".");
827
828 // go through all atoms
829 for (int i=0;i<FillerCount;i++)
830 CopyAtoms[i] = NULL;
831
832 // have same rotation angles for all molecule's atoms
833 if (DoRandomRotation)
834 for (int i=0;i<NDIM;i++)
835 phi[i] = (random()/(rng_max-rng_min))*(2.*M_PI);
836
837 // atom::clone is not const member function, hence we need iterator here
838 for(molecule::iterator iter = filler->begin(); iter !=filler->end();++iter){
839
840 // create atomic random translation vector ...
841 for (int i=0;i<NDIM;i++)
842 AtomTranslations[i] = RandomAtomDisplacement*(random()/((rng_max-rng_min)/2.) - 1.);
843
844 // ... and rotation matrix
845 if (DoRandomRotation) {
846 Rotations.set(0,0, cos(phi[0]) *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2])));
847 Rotations.set(0,1, sin(phi[0]) *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2])));
848 Rotations.set(0,2, cos(phi[1])*sin(phi[2]) );
849 Rotations.set(1,0, -sin(phi[0])*cos(phi[1]) );
850 Rotations.set(1,1, cos(phi[0])*cos(phi[1]) );
851 Rotations.set(1,2, sin(phi[1]) );
852 Rotations.set(2,0, -cos(phi[0]) *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2])));
853 Rotations.set(2,1, -sin(phi[0]) *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2])));
854 Rotations.set(2,2, cos(phi[1])*cos(phi[2]) );
855 }
856
857 // ... and put at new position
858 Inserter = (*iter)->getPosition();
859 if (DoRandomRotation)
860 Inserter *= Rotations;
861 Inserter += AtomTranslations + FillerTranslations + CurrentPosition;
862
863 // check whether inserter is inside box
864 Inserter *= MInverse;
865 FillIt = true;
866 for (int i=0;i<NDIM;i++)
867 FillIt = FillIt && (Inserter[i] >= -MYEPSILON) && ((Inserter[i]-1.) <= MYEPSILON);
868 Inserter *= M;
869
870 // Check whether point is in- or outside
871 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
872 // get linked cell list
873 if (TesselStruct[(*ListRunner)] != NULL) {
874 const double distance = (TesselStruct[(*ListRunner)]->GetDistanceToSurface(Inserter, LCList[(*ListRunner)]));
875 FillIt = FillIt && (distance > boundary) && ((MaxDistance < 0) || (MaxDistance > distance));
876 }
877 }
878 // insert into Filling
879 if (FillIt) {
880 LOG(1, "INFO: Position at " << Inserter << " is outer point.");
881 // copy atom ...
882 CopyAtoms[(*iter)->getNr()] = (*iter)->clone();
883 (*CopyAtoms[(*iter)->getNr()]).setPosition(Inserter);
884 Filling->AddAtom(CopyAtoms[(*iter)->getNr()]);
885 LOG(1, "Filling atom " << **iter << ", translated to " << AtomTranslations << ", at final position is " << (CopyAtoms[(*iter)->getNr()]->getPosition()) << ".");
886 } else {
887 LOG(1, "INFO: Position at " << Inserter << " is inner point, within boundary or outside of MaxDistance.");
888 CopyAtoms[(*iter)->getNr()] = NULL;
889 continue;
890 }
891 }
892 // go through all bonds and add as well
893 for(molecule::iterator AtomRunner = filler->begin(); AtomRunner != filler->end(); ++AtomRunner) {
894 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
895 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
896 BondRunner != ListOfBonds.end();
897 ++BondRunner)
898 if ((*BondRunner)->leftatom == *AtomRunner) {
899 Binder = (*BondRunner);
900 if ((CopyAtoms[Binder->leftatom->getNr()] != NULL) && (CopyAtoms[Binder->rightatom->getNr()] != NULL)) {
901 LOG(3, "Adding Bond between " << *CopyAtoms[Binder->leftatom->getNr()] << " and " << *CopyAtoms[Binder->rightatom->getNr()]<< ".");
902 Filling->AddBond(CopyAtoms[Binder->leftatom->getNr()], CopyAtoms[Binder->rightatom->getNr()], Binder->BondDegree);
903 }
904 }
905 }
906 }
907 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
908 delete LCList[*ListRunner];
909 delete TesselStruct[(*ListRunner)];
910 }
911};
912
913/** Rotates given molecule \a Filling and moves its atoms according to given
914 * \a RandomAtomDisplacement.
915 *
916 * Note that for rotation to be sensible, the molecule should be centered at
917 * the origin. This is not done here!
918 *
919 * \param &Filling molecule whose atoms to displace
920 * \param RandomAtomDisplacement magnitude of random displacement
921 * \param &Rotations 3D rotation matrix (or unity if no rotation desired)
922 */
923void RandomizeMoleculePositions(
924 molecule *&Filling,
925 double RandomAtomDisplacement,
926 RealSpaceMatrix &Rotations,
927 RandomNumberGenerator &random
928 )
929{
930 const double rng_min = random.min();
931 const double rng_max = random.max();
932
933 Vector AtomTranslations;
934 for(molecule::iterator miter = Filling->begin(); miter != Filling->end(); ++miter) {
935 Vector temp = (*miter)->getPosition();
936 temp *= Rotations;
937 (*miter)->setPosition(temp);
938 // create atomic random translation vector ...
939 for (int i=0;i<NDIM;i++)
940 AtomTranslations[i] = RandomAtomDisplacement*(random()/((rng_max-rng_min)/2.) - 1.);
941 (*miter)->setPosition((*miter)->getPosition() + AtomTranslations);
942 }
943}
944
945/** Removes all atoms of a molecule outside.
946 *
947 * If the molecule is empty, it is removed as well.
948 *
949 * @param Filling molecule whose atoms to check, removed if eventually left
950 * empty.
951 * @return true - atoms had to be removed, false - no atoms have been removed
952 */
953bool RemoveAtomsOutsideDomain(molecule *&Filling)
954{
955 bool status = false;
956 Box &Domain = World::getInstance().getDomain();
957 // check if all is still inside domain
958 for(molecule::iterator miter = Filling->begin(); miter != Filling->end(); ) {
959 // check whether each atom is inside box
960 if (!Domain.isInside((*miter)->getPosition())) {
961 status = true;
962 atom *Walker = *miter;
963 ++miter;
964 World::getInstance().destroyAtom(Walker);
965 } else {
966 ++miter;
967 }
968 }
969 if (Filling->empty()) {
970 LOG(0, "Removing molecule " << Filling->getName() << ", all atoms have been removed.");
971 World::getInstance().destroyMolecule(Filling);
972 Filling = NULL;
973 }
974 return status;
975}
976
977/** Checks whether there are no atoms inside a sphere around \a CurrentPosition
978 * except those atoms present in \a *filler.
979 * If filler is NULL, then we just call LinkedCell_deprecated::GetPointsInsideSphere() and
980 * check whether the return list is empty.
981 * @param *filler
982 * @param boundary
983 * @param CurrentPosition
984 */
985bool isSpaceAroundPointVoid(
986 LinkedCell_deprecated *LC,
987 molecule *filler,
988 const double boundary,
989 Vector &CurrentPosition)
990{
991 size_t compareTo = 0;
992 TesselPointSTLList* liste = LC->GetPointsInsideSphere(boundary == 0. ? MYEPSILON : boundary, &CurrentPosition);
993 if (filler != NULL) {
994 for (TesselPointSTLList::const_iterator iter = liste->begin();
995 iter != liste->end();
996 ++iter) {
997 for (molecule::iterator miter = filler->begin();
998 miter != filler->end();
999 ++miter) {
1000 if (*iter == *miter)
1001 ++compareTo;
1002 }
1003 }
1004 }
1005 const bool result = (liste->size() == compareTo);
1006 if (!result) {
1007 LOG(0, "Skipping because of the following atoms:");
1008 for (TesselPointSTLList::const_iterator iter = liste->begin();
1009 iter != liste->end();
1010 ++iter) {
1011 LOG(0, **iter);
1012 }
1013 }
1014 delete(liste);
1015 return result;
1016}
1017
1018/** Sets given 3x3 matrix to a random rotation matrix.
1019 *
1020 * @param a matrix to set
1021 */
1022inline void setRandomRotation(RealSpaceMatrix &a)
1023{
1024 double phi[NDIM];
1025 RandomNumberGenerator &random = RandomNumberGeneratorFactory::getInstance().makeRandomNumberGenerator();
1026 const double rng_min = random.min();
1027 const double rng_max = random.max();
1028
1029 for (int i=0;i<NDIM;i++) {
1030 phi[i] = (random()/(rng_max-rng_min))*(2.*M_PI);
1031 LOG(4, "DEBUG: Random angle is " << phi[i] << ".");
1032 }
1033
1034 a.setRotation(phi);
1035}
1036
1037/** Fills the empty space of the simulation box with water.
1038 * \param *filler molecule which the box is to be filled with
1039 * \param configuration contains box dimensions
1040 * \param distance[NDIM] distance between filling molecules in each direction
1041 * \param boundary length of boundary zone between molecule and filling molecules
1042 * \param RandAtomDisplacement maximum distance for random displacement per atom
1043 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
1044 * \param MinDistance minimum distance to boundary of domain and present molecules
1045 * \param DoRandomRotation true - do random rotations, false - don't
1046 */
1047void FillVoidWithMolecule(
1048 molecule *&filler,
1049 config &configuration,
1050 const double distance[NDIM],
1051 const double boundary,
1052 const double RandomAtomDisplacement,
1053 const double RandomMolDisplacement,
1054 const double MinDistance,
1055 const bool DoRandomRotation
1056 )
1057{
1058 //Info FunctionInfo(__func__);
1059 molecule *Filling = NULL;
1060 Vector CurrentPosition;
1061 int N[NDIM];
1062 int n[NDIM];
1063 const RealSpaceMatrix &M = World::getInstance().getDomain().getM();
1064 RealSpaceMatrix Rotations;
1065 const RealSpaceMatrix &MInverse = World::getInstance().getDomain().getMinv();
1066 Vector FillerTranslations;
1067 Vector FillerDistance;
1068 Vector Inserter;
1069 double FillIt = false;
1070 Vector firstInserter;
1071 bool firstInsertion = true;
1072 const Box &Domain = World::getInstance().getDomain();
1073 map<molecule *, LinkedCell_deprecated *> LCList;
1074 std::vector<molecule *> List = World::getInstance().getAllMolecules();
1075 MoleculeListClass *MolList = World::getInstance().getMolecules();
1076
1077 for (std::vector<molecule *>::iterator ListRunner = List.begin(); ListRunner != List.end(); ListRunner++)
1078 if ((*ListRunner)->getAtomCount() > 0) {
1079 LOG(1, "Pre-creating linked cell lists for molecule " << *ListRunner << ".");
1080 PointCloudAdaptor< molecule > cloud(*ListRunner, (*ListRunner)->name);
1081 LCList[(*ListRunner)] = new LinkedCell_deprecated(cloud, 10.); // get linked cell list
1082 }
1083
1084 // Center filler at its center of gravity
1085 Vector *gravity = filler->DetermineCenterOfGravity();
1086 filler->CenterAtVector(gravity);
1087 delete gravity;
1088 //const int FillerCount = filler->getAtomCount();
1089 LOG(2, "INFO: Filler molecule has the following bonds:");
1090 for(molecule::iterator AtomRunner = filler->begin(); AtomRunner != filler->end(); ++AtomRunner) {
1091 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
1092 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
1093 BondRunner != ListOfBonds.end();
1094 ++BondRunner)
1095 if ((*BondRunner)->leftatom == *AtomRunner)
1096 LOG(2, " " << *(*BondRunner));
1097 }
1098
1099 // calculate filler grid in [0,1]^3
1100 FillerDistance = MInverse * Vector(distance[0], distance[1], distance[2]);
1101 for(int i=0;i<NDIM;i++)
1102 N[i] = (int) ceil(1./FillerDistance[i]);
1103 LOG(1, "INFO: Grid steps are " << N[0] << ", " << N[1] << ", " << N[2] << ".");
1104
1105 // initialize seed of random number generator to current time
1106 RandomNumberGenerator &random = RandomNumberGeneratorFactory::getInstance().makeRandomNumberGenerator();
1107 const double rng_min = random.min();
1108 const double rng_max = random.max();
1109 //srand ( time(NULL) );
1110
1111 // go over [0,1]^3 filler grid
1112 for (n[0] = 0; n[0] < N[0]; n[0]++)
1113 for (n[1] = 0; n[1] < N[1]; n[1]++)
1114 for (n[2] = 0; n[2] < N[2]; n[2]++) {
1115 // calculate position of current grid vector in untransformed box
1116 CurrentPosition = M * Vector((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
1117 // create molecule random translation vector ...
1118 for (int i=0;i<NDIM;i++) // have the random values [-1,1]*RandomMolDisplacement
1119 FillerTranslations[i] = RandomMolDisplacement*(random()/((rng_max-rng_min)/2.) - 1.);
1120 LOG(2, "INFO: Current Position is " << CurrentPosition << "+" << FillerTranslations << ".");
1121
1122 // ... and rotation matrix
1123 if (DoRandomRotation)
1124 setRandomRotation(Rotations);
1125 else
1126 Rotations.setIdentity();
1127
1128
1129 // Check whether there is anything too close by and whether atom is outside of domain
1130 FillIt = true;
1131 for (std::map<molecule *, LinkedCell_deprecated *>::iterator ListRunner = LCList.begin(); ListRunner != LCList.end(); ++ListRunner) {
1132 FillIt = FillIt && isSpaceAroundPointVoid(
1133 ListRunner->second,
1134 (firstInsertion ? filler : NULL),
1135 boundary,
1136 CurrentPosition);
1137 FillIt = FillIt && (Domain.isValid(CurrentPosition))
1138 && ((Domain.DistanceToBoundary(CurrentPosition) - MinDistance) > -MYEPSILON);
1139 if (!FillIt)
1140 break;
1141 }
1142
1143 // insert into Filling
1144 if (FillIt) {
1145 Inserter = CurrentPosition + FillerTranslations;
1146 LOG(1, "INFO: Position at " << Inserter << " is void point.");
1147 // fill!
1148 Filling = filler->CopyMolecule();
1149 RandomizeMoleculePositions(Filling, RandomAtomDisplacement, Rotations, random);
1150 // translation
1151 Filling->Translate(&Inserter);
1152 // remove out-of-bounds atoms
1153 const bool status = RemoveAtomsOutsideDomain(Filling);
1154 if ((firstInsertion) && (!status)) { // no atom has been removed
1155 // remove copied atoms and molecule again
1156 Filling->removeAtomsinMolecule();
1157 World::getInstance().destroyMolecule(Filling);
1158 // and mark is final filler position
1159 Filling = filler;
1160 firstInsertion = false;
1161 firstInserter = Inserter;
1162 } else {
1163 // TODO: Remove when World has no MoleculeListClass anymore
1164 if (Filling)
1165 MolList->insert(Filling);
1166 }
1167 } else {
1168 LOG(1, "INFO: Position at " << Inserter << " is non-void point, within boundary or outside of MaxDistance.");
1169 continue;
1170 }
1171 }
1172
1173 // have we inserted any molecules?
1174 if (firstInsertion) {
1175 // If not remove filler
1176 for(molecule::iterator miter = filler->begin(); !filler->empty(); miter = filler->begin()) {
1177 atom *Walker = *miter;
1178 World::getInstance().destroyAtom(Walker);
1179 }
1180 World::getInstance().destroyMolecule(filler);
1181 } else {
1182 // otherwise translate and randomize to final position
1183 if (DoRandomRotation)
1184 setRandomRotation(Rotations);
1185 else
1186 Rotations.setIdentity();
1187 RandomizeMoleculePositions(filler, RandomAtomDisplacement, Rotations, random);
1188 // translation
1189 filler->Translate(&firstInserter);
1190 // remove out-of-bounds atoms
1191 RemoveAtomsOutsideDomain(filler);
1192 }
1193
1194 LOG(0, MolList->ListOfMolecules.size() << " molecules have been inserted.");
1195
1196 for (std::map<molecule *, LinkedCell_deprecated *>::iterator ListRunner = LCList.begin(); !LCList.empty(); ListRunner = LCList.begin()) {
1197 delete ListRunner->second;
1198 LCList.erase(ListRunner);
1199 }
1200};
1201
1202
1203/** Fills the empty space around other molecules' surface of the simulation box with a filler.
1204 *
1205 * Note that we use \a FindNonConvexBorder to determine the surface of the found molecules.
1206 * There, we use a radius of twice the given \a boundary.
1207 *
1208 * \param *out output stream for debugging
1209 * \param *List list of molecules already present in box
1210 * \param *TesselStruct contains tesselated surface
1211 * \param *filler molecule which the box is to be filled with
1212 * \param configuration contains box dimensions
1213 * \param MaxSurfaceDistance fills in molecules only up to this distance (set to -1 if whole of the domain)
1214 * \param distance[NDIM] distance between filling molecules in each direction
1215 * \param boundary length of boundary zone between molecule and filling molecules
1216 * \param MinDistance distance to boundary of domain which is not filled
1217 * \param RandAtomDisplacement maximum distance for random displacement per atom
1218 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
1219 * \param DoRandomRotation true - do random rotations, false - don't
1220 */
1221void FillBoxWithMolecule(
1222 MoleculeListClass *MolList,
1223 molecule *filler,
1224 config &configuration,
1225 const double MaxSurfaceDistance,
1226 const double distance[NDIM],
1227 const double boundary,
1228 const double MinDistance,
1229 const double RandomAtomDisplacement,
1230 const double RandomMolDisplacement,
1231 const bool DoRandomRotation)
1232{
1233 //Info FunctionInfo(__func__);
1234 molecule *Filling = NULL;
1235 Vector CurrentPosition;
1236 int N[NDIM];
1237 int n[NDIM];
1238 const RealSpaceMatrix &M = World::getInstance().getDomain().getM();
1239 RealSpaceMatrix Rotations;
1240 const RealSpaceMatrix &MInverse = World::getInstance().getDomain().getMinv();
1241 Vector FillerTranslations;
1242 Vector FillerDistance;
1243 Vector Inserter;
1244 double FillIt = false;
1245 Vector firstInserter;
1246 bool firstInsertion = true;
1247 const Box &Domain = World::getInstance().getDomain();
1248 map<molecule *, LinkedCell_deprecated *> LCList;
1249 std::vector<molecule *> List = World::getInstance().getAllMolecules();
1250 map<molecule *, Tesselation *> TesselStruct;
1251
1252 for (MoleculeList::iterator ListRunner = MolList->ListOfMolecules.begin(); ListRunner != MolList->ListOfMolecules.end(); ListRunner++)
1253 if ((*ListRunner)->getAtomCount() > 0) {
1254 LOG(1, "Pre-creating linked cell lists for molecule " << *ListRunner << ".");
1255 PointCloudAdaptor< molecule > cloud(*ListRunner, (*ListRunner)->name);
1256 LCList[(*ListRunner)] = new LinkedCell_deprecated(cloud, 4.*boundary); // get linked cell list
1257 LOG(1, "Pre-creating tesselation for molecule " << *ListRunner << ".");
1258 TesselStruct[(*ListRunner)] = NULL;
1259 FindNonConvexBorder((*ListRunner), TesselStruct[(*ListRunner)], (const LinkedCell_deprecated *&)LCList[(*ListRunner)], 2.*boundary, NULL);
1260 }
1261
1262 // Center filler at origin
1263 filler->CenterEdge(&Inserter);
1264 const int FillerCount = filler->getAtomCount();
1265 LOG(2, "INFO: Filler molecule has the following bonds:");
1266 for(molecule::iterator AtomRunner = filler->begin(); AtomRunner != filler->end(); ++AtomRunner) {
1267 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
1268 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
1269 BondRunner != ListOfBonds.end();
1270 ++BondRunner) {
1271 if ((*BondRunner)->leftatom == *AtomRunner)
1272 LOG(2, " " << *(*BondRunner));
1273 }
1274 }
1275
1276 atom * CopyAtoms[FillerCount];
1277
1278 setVerbosity(4);
1279
1280 // calculate filler grid in [0,1]^3
1281 FillerDistance = MInverse * Vector(distance[0], distance[1], distance[2]);
1282 for(int i=0;i<NDIM;i++)
1283 N[i] = (int) ceil(1./FillerDistance[i]);
1284 LOG(1, "INFO: Grid steps are " << N[0] << ", " << N[1] << ", " << N[2] << ".");
1285
1286 // initialize seed of random number generator to current time
1287 RandomNumberGenerator &random = RandomNumberGeneratorFactory::getInstance().makeRandomNumberGenerator();
1288 const double rng_min = random.min();
1289 const double rng_max = random.max();
1290 //srand ( time(NULL) );
1291
1292 // go over [0,1]^3 filler grid
1293 for (n[0] = 0; n[0] < N[0]; n[0]++)
1294 for (n[1] = 0; n[1] < N[1]; n[1]++)
1295 for (n[2] = 0; n[2] < N[2]; n[2]++) {
1296 // calculate position of current grid vector in untransformed box
1297 CurrentPosition = M * Vector((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
1298 // create molecule random translation vector ...
1299 for (int i=0;i<NDIM;i++)
1300 FillerTranslations[i] = RandomMolDisplacement*(random()/((rng_max-rng_min)/2.) - 1.);
1301 LOG(1, "INFO: Current Position is " << CurrentPosition << "+" << FillerTranslations << ".");
1302
1303 // ... and rotation matrix
1304 if (DoRandomRotation)
1305 setRandomRotation(Rotations);
1306 else
1307 Rotations.setIdentity();
1308
1309
1310 // Check whether there is anything too close by and whether atom is outside of domain
1311 FillIt = true;
1312 for (std::map<molecule *, LinkedCell_deprecated *>::iterator ListRunner = LCList.begin(); ListRunner != LCList.end(); ++ListRunner) {
1313 // check whether its void
1314 FillIt = FillIt && isSpaceAroundPointVoid(
1315 ListRunner->second,
1316 (firstInsertion ? filler : NULL),
1317 boundary,
1318 CurrentPosition);
1319 if (!FillIt) {
1320 LOG(2, "REJECT: Position at " << Inserter << " is non-void.");
1321 break;
1322 }
1323 // check whether inside domain
1324 FillIt = FillIt && (Domain.isValid(CurrentPosition));
1325 if (!FillIt) {
1326 LOG(2, "REJECT: Position at " << CurrentPosition << " is "
1327 << distance << ", hence outside of domain.");
1328 break;
1329 }
1330 // check minimum distance to boundary
1331 const double distance = (Domain.DistanceToBoundary(CurrentPosition) - MinDistance);
1332 FillIt = FillIt && (distance > -MYEPSILON);
1333 if (!FillIt) {
1334 LOG(2, "REJECT: Position at " << CurrentPosition << " is " << distance << ", less than "
1335 << MinDistance << " hence, too close to boundary.");
1336 break;
1337 }
1338 }
1339 // Check whether point is in- or outside of tesselations
1340 if (FillIt) {
1341 for (MoleculeList::iterator ListRunner = MolList->ListOfMolecules.begin(); ListRunner != MolList->ListOfMolecules.end(); ListRunner++) {
1342 // get linked cell list
1343 if (TesselStruct[(*ListRunner)] != NULL) {
1344 const double distance = (TesselStruct[(*ListRunner)]->GetDistanceToSurface(Inserter, LCList[(*ListRunner)]));
1345 LOG(2, "INFO: Distance to surface is " << distance << ".");
1346 FillIt = FillIt && ((distance == -1.) || (distance > boundary)) && ((MaxSurfaceDistance < 0) || (MaxSurfaceDistance > distance));
1347 if (!FillIt) {
1348 LOG(2, "REJECT: Position at " << CurrentPosition << " is in distance of " << distance
1349 << " to a surface, less than " << MaxSurfaceDistance << " hence, too close.");
1350 break;
1351 }
1352 }
1353 }
1354 }
1355
1356 // insert into Filling
1357 if (FillIt) {
1358 Inserter = CurrentPosition + FillerTranslations;
1359 LOG(2, "ACCEPT: Position at " << CurrentPosition << " is void point.");
1360 // fill!
1361 Filling = filler->CopyMolecule();
1362 RandomizeMoleculePositions(Filling, RandomAtomDisplacement, Rotations, random);
1363 // translation
1364 Filling->Translate(&Inserter);
1365 // remove out-of-bounds atoms
1366 const bool status = RemoveAtomsOutsideDomain(Filling);
1367 if ((firstInsertion) && (!status)) { // no atom has been removed
1368 // remove copied atoms and molecule again
1369 Filling->removeAtomsinMolecule();
1370 World::getInstance().destroyMolecule(Filling);
1371 // and mark is final filler position
1372 Filling = filler;
1373 firstInsertion = false;
1374 firstInserter = Inserter;
1375 } else {
1376 // TODO: Remove when World has no MoleculeListClass anymore
1377 if (Filling)
1378 MolList->insert(Filling);
1379 }
1380 } else {
1381 LOG(2, "REJECT: Position at " << CurrentPosition << " is non-void point, within boundary or outside of MaxSurfaceDistance.");
1382 continue;
1383 }
1384 }
1385
1386 // have we inserted any molecules?
1387 if (firstInsertion) {
1388 // If not remove filler
1389 for(molecule::iterator miter = filler->begin(); !filler->empty(); miter = filler->begin()) {
1390 atom *Walker = *miter;
1391 World::getInstance().destroyAtom(Walker);
1392 }
1393 World::getInstance().destroyMolecule(filler);
1394 } else {
1395 // otherwise translate and randomize to final position
1396 if (DoRandomRotation)
1397 setRandomRotation(Rotations);
1398 else
1399 Rotations.setIdentity();
1400 RandomizeMoleculePositions(filler, RandomAtomDisplacement, Rotations, random);
1401 // translation
1402 filler->Translate(&firstInserter);
1403 // remove out-of-bounds atoms
1404 RemoveAtomsOutsideDomain(filler);
1405 }
1406
1407 LOG(0, MolList->ListOfMolecules.size() << " molecules have been inserted.");
1408
1409 for (std::map<molecule *, LinkedCell_deprecated *>::iterator ListRunner = LCList.begin(); !LCList.empty(); ListRunner = LCList.begin()) {
1410 delete ListRunner->second;
1411 LCList.erase(ListRunner);
1412 }
1413};
1414
1415/** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
1416 * \param *out output stream for debugging
1417 * \param *mol molecule structure with Atom's and Bond's
1418 * \param *&TesselStruct Tesselation filled with points, lines and triangles on boundary on return
1419 * \param *&LCList atoms in LinkedCell_deprecated list
1420 * \param RADIUS radius of the virtual sphere
1421 * \param *filename filename prefix for output of vertex data
1422 * \return true - tesselation successful, false - tesselation failed
1423 */
1424bool FindNonConvexBorder(molecule* const mol, Tesselation *&TesselStruct, const LinkedCell_deprecated *&LCList, const double RADIUS, const char *filename = NULL)
1425{
1426 //Info FunctionInfo(__func__);
1427 bool freeLC = false;
1428 bool status = false;
1429 CandidateForTesselation *baseline = NULL;
1430 bool OneLoopWithoutSuccessFlag = true; // marks whether we went once through all baselines without finding any without two triangles
1431 bool TesselationFailFlag = false;
1432
1433 mol->getAtomCount();
1434
1435 if (TesselStruct == NULL) {
1436 LOG(1, "Allocating Tesselation struct ...");
1437 TesselStruct= new Tesselation;
1438 } else {
1439 delete(TesselStruct);
1440 LOG(1, "Re-Allocating Tesselation struct ...");
1441 TesselStruct = new Tesselation;
1442 }
1443
1444 // initialise Linked Cell
1445 PointCloudAdaptor< molecule > cloud(mol, mol->name);
1446 if (LCList == NULL) {
1447 LCList = new LinkedCell_deprecated(cloud, 2.*RADIUS);
1448 freeLC = true;
1449 }
1450
1451 // 1. get starting triangle
1452 if (!TesselStruct->FindStartingTriangle(RADIUS, LCList)) {
1453 ELOG(0, "No valid starting triangle found.");
1454 //performCriticalExit();
1455 }
1456 if (filename != NULL) {
1457 if ((DoSingleStepOutput && ((TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
1458 TesselStruct->Output(filename, cloud);
1459 }
1460 }
1461
1462 // 2. expand from there
1463 while ((!TesselStruct->OpenLines.empty()) && (OneLoopWithoutSuccessFlag)) {
1464 (cerr << "There are " << TesselStruct->TrianglesOnBoundary.size() << " triangles and " << TesselStruct->OpenLines.size() << " open lines to scan for candidates." << endl);
1465 // 2a. print OpenLines without candidates
1466 LOG(1, "There are the following open lines to scan for a candidates:");
1467 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
1468 if (Runner->second->pointlist.empty())
1469 LOG(1, " " << *(Runner->second));
1470
1471 // 2b. find best candidate for each OpenLine
1472 TesselationFailFlag = TesselStruct->FindCandidatesforOpenLines(RADIUS, LCList);
1473
1474 // 2c. print OpenLines with candidates again
1475 LOG(1, "There are " << TesselStruct->OpenLines.size() << " open lines to scan for the best candidates:");
1476 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
1477 LOG(1, " " << *(Runner->second));
1478
1479 // 2d. search for smallest ShortestAngle among all candidates
1480 double ShortestAngle = 4.*M_PI;
1481 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++) {
1482 if (Runner->second->ShortestAngle < ShortestAngle) {
1483 baseline = Runner->second;
1484 ShortestAngle = baseline->ShortestAngle;
1485 LOG(1, "New best candidate is " << *baseline->BaseLine << " with point " << *(*baseline->pointlist.begin()) << " and angle " << baseline->ShortestAngle);
1486 }
1487 }
1488 // 2e. if we found one, add candidate
1489 if ((ShortestAngle == 4.*M_PI) || (baseline->pointlist.empty()))
1490 OneLoopWithoutSuccessFlag = false;
1491 else {
1492 TesselStruct->AddCandidatePolygon(*baseline, RADIUS, LCList);
1493 }
1494
1495 // 2f. write temporary envelope
1496 if (filename != NULL) {
1497 if ((DoSingleStepOutput && ((TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
1498 TesselStruct->Output(filename, cloud);
1499 }
1500 }
1501 }
1502// // check envelope for consistency
1503// status = CheckListOfBaselines(TesselStruct);
1504//
1505// // look whether all points are inside of the convex envelope, otherwise add them via degenerated triangles
1506// //->InsertStraddlingPoints(mol, LCList);
1507// for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
1508// class TesselPoint *Runner = NULL;
1509// Runner = *iter;
1510// LOG(1, "Checking on " << Runner->Name << " ... ");
1511// if (!->IsInnerPoint(Runner, LCList)) {
1512// LOG(2, Runner->Name << " is outside of envelope, adding via degenerated triangles.");
1513// ->AddBoundaryPointByDegeneratedTriangle(Runner, LCList);
1514// } else {
1515// LOG(2, Runner->Name << " is inside of or on envelope.");
1516// }
1517// }
1518
1519// // Purges surplus triangles.
1520// TesselStruct->RemoveDegeneratedTriangles();
1521//
1522// // check envelope for consistency
1523// status = CheckListOfBaselines(TesselStruct);
1524
1525 cout << "before correction" << endl;
1526
1527 // store before correction
1528 StoreTrianglesinFile(mol, TesselStruct, filename, "");
1529
1530// // correct degenerated polygons
1531// TesselStruct->CorrectAllDegeneratedPolygons();
1532//
1533 // check envelope for consistency
1534 status = CheckListOfBaselines(TesselStruct);
1535
1536 // write final envelope
1537 CalculateConcavityPerBoundaryPoint(TesselStruct);
1538 cout << "after correction" << endl;
1539 StoreTrianglesinFile(mol, TesselStruct, filename, "");
1540
1541 if (freeLC)
1542 delete(LCList);
1543
1544 return status;
1545};
1546
1547
1548/** Finds a hole of sufficient size in \a *mols to embed \a *srcmol into it.
1549 * \param *out output stream for debugging
1550 * \param *mols molecules in the domain to embed in between
1551 * \param *srcmol embedding molecule
1552 * \return *Vector new center of \a *srcmol for embedding relative to \a this
1553 */
1554Vector* FindEmbeddingHole(MoleculeListClass *mols, molecule *srcmol)
1555{
1556 //Info FunctionInfo(__func__);
1557 Vector *Center = new Vector;
1558 Center->Zero();
1559 // calculate volume/shape of \a *srcmol
1560
1561 // find embedding holes
1562
1563 // if more than one, let user choose
1564
1565 // return embedding center
1566 return Center;
1567};
1568
Note: See TracBrowser for help on using the repository browser.