source: src/boundary.cpp@ 8e17d6

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 8e17d6 was 986ed3, checked in by Tillmann Crueger <crueger@…>, 15 years ago

COMPILE_SPEEDUP: Replaced all implicit inclusions of iostream with forwards

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