source: src/boundary.cpp@ 753f02

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 Candidate_v1.7.0 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 753f02 was 1bd79e, checked in by Tillmann Crueger <crueger@…>, 16 years ago

Changed implementation of Vector to forward operations to contained objects

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