source: src/boundary.cpp@ 9cd807

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 9cd807 was 6b5657, checked in by Frederik Heber <heber@…>, 14 years ago

Decoupled typedef for some STL maps used in boundary.cpp from those used in molecule_dynamics.cpp

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