source: src/boundary.cpp@ 0d1ad0

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 0d1ad0 was 112b09, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Added #include "Helpers/MemDebug.hpp" to all .cpp files

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