source: src/boundary.cpp@ 0e01b4

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

Merge branch 'VectorRefactoring' into StructureRefactoring

Conflicts:

molecuilder/src/Legacy/oldmenu.cpp
molecuilder/src/Makefile.am
molecuilder/src/analysis_correlation.cpp
molecuilder/src/boundary.cpp
molecuilder/src/builder.cpp
molecuilder/src/config.cpp
molecuilder/src/ellipsoid.cpp
molecuilder/src/linkedcell.cpp
molecuilder/src/molecule.cpp
molecuilder/src/molecule_fragmentation.cpp
molecuilder/src/molecule_geometry.cpp
molecuilder/src/molecule_graph.cpp
molecuilder/src/moleculelist.cpp
molecuilder/src/tesselation.cpp
molecuilder/src/tesselationhelpers.cpp
molecuilder/src/unittests/AnalysisCorrelationToSurfaceUnitTest.cpp
molecuilder/src/unittests/bondgraphunittest.cpp
molecuilder/src/vector.cpp
molecuilder/src/vector.hpp

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