source: src/boundary.cpp@ 3c349b

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

"not working parsed molecule into subgraph splitting"-BUG fixed, BugFinder branch can be closed.

  • config::Load() - atoms were not in the right order for MaxOrder-test (12). Hence, the BondFragmentAdjacency could not be parsed. Now, we just take the subgraphs as the association of each atom to a molecule, i.e. we make a list and then re-link each atom to its new connected subgraph molecule, which is returned as the MoleculeListClass.

other fixes:

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