source: src/boundary.cpp@ 7e37a3

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

Merge branch 'AtomicPositionEncapsulation' into stable

Conflicts:

src/Actions/AtomAction/ChangeElementAction.cpp
src/Actions/WorldAction/RemoveSphereOfAtomsAction.cpp
src/Makefile.am
src/UIElements/TextUI/TextDialog.cpp
src/analysis_correlation.hpp
src/atom.cpp
src/atom_atominfo.hpp
src/bond.cpp
src/boundary.cpp
src/molecule_geometry.cpp
src/tesselation.cpp
src/tesselationhelpers.cpp
src/triangleintersectionlist.cpp
src/unittests/Makefile.am

  • fixed #includes due to moves to Helpers and LinearAlgebra
  • moved VectorInterface.* and vector_ops.* to LinearAlgebra
  • no more direct access of atom::node, remapped to set/getPosition()
  • no more direct access to atom::type, remapped to set/getType() (also in atom due to derivation and atominfo::AtomicElement is private not protected).
  • 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 filler->Center.Zero();
807 const int FillerCount = filler->getAtomCount();
808 DoLog(2) && (Log() << Verbose(2) << "INFO: Filler molecule has the following bonds:" << endl);
809 for(molecule::iterator AtomRunner = filler->begin(); AtomRunner != filler->end(); ++AtomRunner)
810 for(BondList::iterator BondRunner = (*AtomRunner)->ListOfBonds.begin(); BondRunner != (*AtomRunner)->ListOfBonds.end(); ++BondRunner)
811 if ((*BondRunner)->leftatom == *AtomRunner)
812 DoLog(2) && (Log() << Verbose(2) << " " << *(*BondRunner) << endl);
813
814 atom * CopyAtoms[FillerCount];
815
816 // calculate filler grid in [0,1]^3
817 FillerDistance = MInverse * Vector(distance[0], distance[1], distance[2]);
818 for(int i=0;i<NDIM;i++)
819 N[i] = (int) ceil(1./FillerDistance[i]);
820 DoLog(1) && (Log() << Verbose(1) << "INFO: Grid steps are " << N[0] << ", " << N[1] << ", " << N[2] << "." << endl);
821
822 // initialize seed of random number generator to current time
823 srand ( time(NULL) );
824
825 // go over [0,1]^3 filler grid
826 for (n[0] = 0; n[0] < N[0]; n[0]++)
827 for (n[1] = 0; n[1] < N[1]; n[1]++)
828 for (n[2] = 0; n[2] < N[2]; n[2]++) {
829 // calculate position of current grid vector in untransformed box
830 CurrentPosition = M * Vector((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
831 // create molecule random translation vector ...
832 for (int i=0;i<NDIM;i++)
833 FillerTranslations[i] = RandomMolDisplacement*(rand()/(RAND_MAX/2.) - 1.);
834 DoLog(2) && (Log() << Verbose(2) << "INFO: Current Position is " << CurrentPosition << "+" << FillerTranslations << "." << endl);
835
836 // go through all atoms
837 for (int i=0;i<FillerCount;i++)
838 CopyAtoms[i] = NULL;
839 for(molecule::const_iterator iter = filler->begin(); iter !=filler->end();++iter){
840
841 // create atomic random translation vector ...
842 for (int i=0;i<NDIM;i++)
843 AtomTranslations[i] = RandomAtomDisplacement*(rand()/(RAND_MAX/2.) - 1.);
844
845 // ... and rotation matrix
846 if (DoRandomRotation) {
847 for (int i=0;i<NDIM;i++) {
848 phi[i] = rand()/(RAND_MAX/(2.*M_PI));
849 }
850
851 Rotations.set(0,0, cos(phi[0]) *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2])));
852 Rotations.set(0,1, sin(phi[0]) *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2])));
853 Rotations.set(0,2, cos(phi[1])*sin(phi[2]) );
854 Rotations.set(1,0, -sin(phi[0])*cos(phi[1]) );
855 Rotations.set(1,1, cos(phi[0])*cos(phi[1]) );
856 Rotations.set(1,2, sin(phi[1]) );
857 Rotations.set(2,0, -cos(phi[0]) *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2])));
858 Rotations.set(2,1, -sin(phi[0]) *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2])));
859 Rotations.set(2,2, cos(phi[1])*cos(phi[2]) );
860 }
861
862 // ... and put at new position
863 Inserter = (*iter)->getPosition();
864 if (DoRandomRotation)
865 Inserter *= Rotations;
866 Inserter += AtomTranslations + FillerTranslations + CurrentPosition;
867
868 // check whether inserter is inside box
869 Inserter *= MInverse;
870 FillIt = true;
871 for (int i=0;i<NDIM;i++)
872 FillIt = FillIt && (Inserter[i] >= -MYEPSILON) && ((Inserter[i]-1.) <= MYEPSILON);
873 Inserter *= M;
874
875 // Check whether point is in- or outside
876 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
877 // get linked cell list
878 if (TesselStruct[(*ListRunner)] != NULL) {
879 const double distance = (TesselStruct[(*ListRunner)]->GetDistanceToSurface(Inserter, LCList[(*ListRunner)]));
880 FillIt = FillIt && (distance > boundary) && ((MaxDistance < 0) || (MaxDistance > distance));
881 }
882 }
883 // insert into Filling
884 if (FillIt) {
885 DoLog(1) && (Log() << Verbose(1) << "INFO: Position at " << Inserter << " is outer point." << endl);
886 // copy atom ...
887 CopyAtoms[(*iter)->nr] = (*iter)->clone();
888 (*CopyAtoms[(*iter)->nr]).setPosition(Inserter);
889 Filling->AddAtom(CopyAtoms[(*iter)->nr]);
890 DoLog(1) && (Log() << Verbose(1) << "Filling atom " << **iter << ", translated to " << AtomTranslations << ", at final position is " << (CopyAtoms[(*iter)->nr]->getPosition()) << "." << endl);
891 } else {
892 DoLog(1) && (Log() << Verbose(1) << "INFO: Position at " << Inserter << " is inner point, within boundary or outside of MaxDistance." << endl);
893 CopyAtoms[(*iter)->nr] = NULL;
894 continue;
895 }
896 }
897 // go through all bonds and add as well
898 for(molecule::iterator AtomRunner = filler->begin(); AtomRunner != filler->end(); ++AtomRunner)
899 for(BondList::iterator BondRunner = (*AtomRunner)->ListOfBonds.begin(); BondRunner != (*AtomRunner)->ListOfBonds.end(); ++BondRunner)
900 if ((*BondRunner)->leftatom == *AtomRunner) {
901 Binder = (*BondRunner);
902 if ((CopyAtoms[Binder->leftatom->nr] != NULL) && (CopyAtoms[Binder->rightatom->nr] != NULL)) {
903 Log() << Verbose(3) << "Adding Bond between " << *CopyAtoms[Binder->leftatom->nr] << " and " << *CopyAtoms[Binder->rightatom->nr]<< "." << endl;
904 Filling->AddBond(CopyAtoms[Binder->leftatom->nr], CopyAtoms[Binder->rightatom->nr], Binder->BondDegree);
905 }
906 }
907 }
908 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
909 delete LCList[*ListRunner];
910 delete TesselStruct[(*ListRunner)];
911 }
912
913 return Filling;
914};
915
916
917/** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
918 * \param *out output stream for debugging
919 * \param *mol molecule structure with Atom's and Bond's
920 * \param *&TesselStruct Tesselation filled with points, lines and triangles on boundary on return
921 * \param *&LCList atoms in LinkedCell list
922 * \param RADIUS radius of the virtual sphere
923 * \param *filename filename prefix for output of vertex data
924 * \return true - tesselation successful, false - tesselation failed
925 */
926bool FindNonConvexBorder(const molecule* const mol, Tesselation *&TesselStruct, const LinkedCell *&LCList, const double RADIUS, const char *filename = NULL)
927{
928 Info FunctionInfo(__func__);
929 bool freeLC = false;
930 bool status = false;
931 CandidateForTesselation *baseline = NULL;
932 bool OneLoopWithoutSuccessFlag = true; // marks whether we went once through all baselines without finding any without two triangles
933 bool TesselationFailFlag = false;
934
935 mol->getAtomCount();
936
937 if (TesselStruct == NULL) {
938 DoLog(1) && (Log() << Verbose(1) << "Allocating Tesselation struct ..." << endl);
939 TesselStruct= new Tesselation;
940 } else {
941 delete(TesselStruct);
942 DoLog(1) && (Log() << Verbose(1) << "Re-Allocating Tesselation struct ..." << endl);
943 TesselStruct = new Tesselation;
944 }
945
946 // initialise Linked Cell
947 if (LCList == NULL) {
948 LCList = new LinkedCell(mol, 2.*RADIUS);
949 freeLC = true;
950 }
951
952 // 1. get starting triangle
953 if (!TesselStruct->FindStartingTriangle(RADIUS, LCList)) {
954 DoeLog(0) && (eLog() << Verbose(0) << "No valid starting triangle found." << endl);
955 //performCriticalExit();
956 }
957 if (filename != NULL) {
958 if ((DoSingleStepOutput && ((TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
959 TesselStruct->Output(filename, mol);
960 }
961 }
962
963 // 2. expand from there
964 while ((!TesselStruct->OpenLines.empty()) && (OneLoopWithoutSuccessFlag)) {
965 (cerr << "There are " << TesselStruct->TrianglesOnBoundary.size() << " triangles and " << TesselStruct->OpenLines.size() << " open lines to scan for candidates." << endl);
966 // 2a. print OpenLines without candidates
967 DoLog(1) && (Log() << Verbose(1) << "There are the following open lines to scan for a candidates:" << endl);
968 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
969 if (Runner->second->pointlist.empty())
970 DoLog(1) && (Log() << Verbose(1) << " " << *(Runner->second) << endl);
971
972 // 2b. find best candidate for each OpenLine
973 TesselationFailFlag = TesselStruct->FindCandidatesforOpenLines(RADIUS, LCList);
974
975 // 2c. print OpenLines with candidates again
976 DoLog(1) && (Log() << Verbose(1) << "There are " << TesselStruct->OpenLines.size() << " open lines to scan for the best candidates:" << endl);
977 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
978 DoLog(1) && (Log() << Verbose(1) << " " << *(Runner->second) << endl);
979
980 // 2d. search for smallest ShortestAngle among all candidates
981 double ShortestAngle = 4.*M_PI;
982 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++) {
983 if (Runner->second->ShortestAngle < ShortestAngle) {
984 baseline = Runner->second;
985 ShortestAngle = baseline->ShortestAngle;
986 DoLog(1) && (Log() << Verbose(1) << "New best candidate is " << *baseline->BaseLine << " with point " << *(*baseline->pointlist.begin()) << " and angle " << baseline->ShortestAngle << endl);
987 }
988 }
989 // 2e. if we found one, add candidate
990 if ((ShortestAngle == 4.*M_PI) || (baseline->pointlist.empty()))
991 OneLoopWithoutSuccessFlag = false;
992 else {
993 TesselStruct->AddCandidatePolygon(*baseline, RADIUS, LCList);
994 }
995
996 // 2f. 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(filename, mol);
1000 }
1001 }
1002 }
1003// // check envelope for consistency
1004// status = CheckListOfBaselines(TesselStruct);
1005//
1006// // look whether all points are inside of the convex envelope, otherwise add them via degenerated triangles
1007// //->InsertStraddlingPoints(mol, LCList);
1008// for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
1009// class TesselPoint *Runner = NULL;
1010// Runner = *iter;
1011// Log() << Verbose(1) << "Checking on " << Runner->Name << " ... " << endl;
1012// if (!->IsInnerPoint(Runner, LCList)) {
1013// Log() << Verbose(2) << Runner->Name << " is outside of envelope, adding via degenerated triangles." << endl;
1014// ->AddBoundaryPointByDegeneratedTriangle(Runner, LCList);
1015// } else {
1016// Log() << Verbose(2) << Runner->Name << " is inside of or on envelope." << endl;
1017// }
1018// }
1019
1020// // Purges surplus triangles.
1021// TesselStruct->RemoveDegeneratedTriangles();
1022//
1023// // check envelope for consistency
1024// status = CheckListOfBaselines(TesselStruct);
1025
1026 cout << "before correction" << endl;
1027
1028 // store before correction
1029 StoreTrianglesinFile(mol, TesselStruct, filename, "");
1030
1031// // correct degenerated polygons
1032// TesselStruct->CorrectAllDegeneratedPolygons();
1033//
1034// // check envelope for consistency
1035// status = CheckListOfBaselines(TesselStruct);
1036
1037 // write final envelope
1038 CalculateConcavityPerBoundaryPoint(TesselStruct);
1039 cout << "after correction" << endl;
1040 StoreTrianglesinFile(mol, TesselStruct, filename, "");
1041
1042 if (freeLC)
1043 delete(LCList);
1044
1045 return status;
1046};
1047
1048
1049/** Finds a hole of sufficient size in \a *mols to embed \a *srcmol into it.
1050 * \param *out output stream for debugging
1051 * \param *mols molecules in the domain to embed in between
1052 * \param *srcmol embedding molecule
1053 * \return *Vector new center of \a *srcmol for embedding relative to \a this
1054 */
1055Vector* FindEmbeddingHole(MoleculeListClass *mols, molecule *srcmol)
1056{
1057 Info FunctionInfo(__func__);
1058 Vector *Center = new Vector;
1059 Center->Zero();
1060 // calculate volume/shape of \a *srcmol
1061
1062 // find embedding holes
1063
1064 // if more than one, let user choose
1065
1066 // return embedding center
1067 return Center;
1068};
1069
Note: See TracBrowser for help on using the repository browser.