source: src/boundary.cpp@ 190326

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

Simplified tesselation.cpp by allowing direct access to derived triangle internals

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