source: src/boundary.cpp@ 436f04

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

Made the ReturnFullMatrixForSymmetric return a Matrix object directely instead of a double array

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