source: src/boundary.cpp@ dc322a

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 dc322a was 255829, checked in by Frederik Heber <heber@…>, 14 years ago

Removed Helpers.hpp, deleted Helpers.cpp and libMoleCuilderHelpers.la is history.

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