source: src/boundary.cpp@ c72112

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

Repaired GetMAxId() method of molecule

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