source: src/Tesselation/boundary.cpp@ b4f72c

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 b4f72c was 94d5ac6, checked in by Frederik Heber <heber@…>, 12 years ago

FIX: As we use GSL internally, we are as of now required to use GPL v2 license.

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