source: src/boundary.cpp@ 36166d

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 36166d was 36166d, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Removed left over parts from old memory-tracker

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