source: src/Tesselation/boundary.cpp@ 5aaa43

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

FIX: Fixed new copyright line since start of 2013 in CodeChecks test.

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