source: src/boundary.cpp@ 6056f1

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 6056f1 was 7f4bee, checked in by Frederik Heber <heber@…>, 15 years ago

LEAKFIX: FillBoxWithMolecule() had mismatch delete/delete[]

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