source: src/boundary.cpp@ bbbad5

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

Removed molecule::Center.

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