source: src/boundary.cpp@ f2bb0f

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 f2bb0f was 9879f6, checked in by Frederik Heber <heber@…>, 15 years ago

Huge Refactoring due to class molecule now being an STL container.

  • molecule::start and molecule::end were dropped. Hence, the usual construct Walker = start while (Walker->next != end) {

Walker = walker->next
...

}
was changed to
for (molecule::iterator iter = begin(); iter != end(); ++iter) {

...

}
and (*iter) used instead of Walker.

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