source: src/boundary.cpp@ e0ba10

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 e0ba10 was 6e5084, checked in by Frederik Heber <heber@…>, 15 years ago

Fixed PrincipalAxisSystemAction.

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