source: src/Tesselation/boundary.cpp@ df9f20

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 df9f20 was 833b15, checked in by Frederik Heber <heber@…>, 11 years ago

FIX: Changes to function signatures in molecule_geometry.

  • no more returning allocated pointer (Vector *)
  • no more Pointers as parameters.
  • removed functions that are only convenience and have nothing to do with the molecule.
  • changes elsewhere due to signature changes.
  • Property mode set to 100644
File size: 68.3 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 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();
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 {
751 RealSpaceMatrix domain;
752 for(int i =0; i<NDIM;++i)
753 domain.at(i,i) = BoxLengths[i];
754 World::getInstance().setDomain(domain);
755 }
756 mol->CenterInBox();
757 }
758 delete[] GreatestDiameter;
759 // update Box of atoms by boundary
760 {
761 RealSpaceMatrix domain;
762 for(int i =0; i<NDIM;++i)
763 domain.at(i,i) = BoxLengths[i];
764 World::getInstance().setDomain(domain);
765 }
766 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.");
767};
768
769
770/** Fills the empty space around other molecules' surface of the simulation box with a filler.
771 * \param *out output stream for debugging
772 * \param *List list of molecules already present in box
773 * \param *TesselStruct contains tesselated surface
774 * \param *filler molecule which the box is to be filled with
775 * \param configuration contains box dimensions
776 * \param MaxDistance fills in molecules only up to this distance (set to -1 if whole of the domain)
777 * \param distance[NDIM] distance between filling molecules in each direction
778 * \param boundary length of boundary zone between molecule and filling mollecules
779 * \param epsilon distance to surface which is not filled
780 * \param RandAtomDisplacement maximum distance for random displacement per atom
781 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
782 * \param DoRandomRotation true - do random rotiations, false - don't
783 */
784void 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)
785{
786 //Info FunctionInfo(__func__);
787 molecule *Filling = World::getInstance().createMolecule();
788 Vector CurrentPosition;
789 int N[NDIM];
790 int n[NDIM];
791 const RealSpaceMatrix &M = World::getInstance().getDomain().getM();
792 RealSpaceMatrix Rotations;
793 const RealSpaceMatrix &MInverse = World::getInstance().getDomain().getMinv();
794 Vector AtomTranslations;
795 Vector FillerTranslations;
796 Vector FillerDistance;
797 Vector Inserter;
798 double FillIt = false;
799 bond::ptr Binder;
800 double phi[NDIM];
801 map<molecule *, Tesselation *> TesselStruct;
802 map<molecule *, LinkedCell_deprecated *> LCList;
803
804 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++)
805 if ((*ListRunner)->getAtomCount() > 0) {
806 LOG(1, "Pre-creating linked cell lists for molecule " << *ListRunner << ".");
807 PointCloudAdaptor< molecule > cloud(*ListRunner, (*ListRunner)->name);
808 LCList[(*ListRunner)] = new LinkedCell_deprecated(cloud, 10.); // get linked cell list
809 LOG(1, "Pre-creating tesselation for molecule " << *ListRunner << ".");
810 TesselStruct[(*ListRunner)] = NULL;
811 FindNonConvexBorder((*ListRunner), TesselStruct[(*ListRunner)], (const LinkedCell_deprecated *&)LCList[(*ListRunner)], 5., NULL);
812 }
813
814 // Center filler at origin
815 filler->CenterEdge();
816 const int FillerCount = filler->getAtomCount();
817 LOG(2, "INFO: Filler molecule has the following bonds:");
818 for(molecule::iterator AtomRunner = filler->begin(); AtomRunner != filler->end(); ++AtomRunner) {
819 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
820 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
821 BondRunner != ListOfBonds.end();
822 ++BondRunner) {
823 if ((*BondRunner)->leftatom == *AtomRunner)
824 LOG(2, " " << *(*BondRunner));
825 }
826 }
827
828 atom * CopyAtoms[FillerCount];
829
830 // calculate filler grid in [0,1]^3
831 FillerDistance = MInverse * Vector(distance[0], distance[1], distance[2]);
832 for(int i=0;i<NDIM;i++)
833 N[i] = (int) ceil(1./FillerDistance[i]);
834 LOG(1, "INFO: Grid steps are " << N[0] << ", " << N[1] << ", " << N[2] << ".");
835
836 // initialize seed of random number generator to current time
837 RandomNumberGenerator &random = RandomNumberGeneratorFactory::getInstance().makeRandomNumberGenerator();
838 const double rng_min = random.min();
839 const double rng_max = random.max();
840 //srand ( time(NULL) );
841
842 // go over [0,1]^3 filler grid
843 for (n[0] = 0; n[0] < N[0]; n[0]++)
844 for (n[1] = 0; n[1] < N[1]; n[1]++)
845 for (n[2] = 0; n[2] < N[2]; n[2]++) {
846 // calculate position of current grid vector in untransformed box
847 CurrentPosition = M * Vector((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
848 // create molecule random translation vector ...
849 for (int i=0;i<NDIM;i++)
850 FillerTranslations[i] = RandomMolDisplacement*(random()/((rng_max-rng_min)/2.) - 1.);
851 LOG(2, "INFO: Current Position is " << CurrentPosition << "+" << FillerTranslations << ".");
852
853 // go through all atoms
854 for (int i=0;i<FillerCount;i++)
855 CopyAtoms[i] = NULL;
856
857 // have same rotation angles for all molecule's atoms
858 if (DoRandomRotation)
859 for (int i=0;i<NDIM;i++)
860 phi[i] = (random()/(rng_max-rng_min))*(2.*M_PI);
861
862 // atom::clone is not const member function, hence we need iterator here
863 for(molecule::iterator iter = filler->begin(); iter !=filler->end();++iter){
864
865 // create atomic random translation vector ...
866 for (int i=0;i<NDIM;i++)
867 AtomTranslations[i] = RandomAtomDisplacement*(random()/((rng_max-rng_min)/2.) - 1.);
868
869 // ... and rotation matrix
870 if (DoRandomRotation) {
871 Rotations.set(0,0, cos(phi[0]) *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2])));
872 Rotations.set(0,1, sin(phi[0]) *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2])));
873 Rotations.set(0,2, cos(phi[1])*sin(phi[2]) );
874 Rotations.set(1,0, -sin(phi[0])*cos(phi[1]) );
875 Rotations.set(1,1, cos(phi[0])*cos(phi[1]) );
876 Rotations.set(1,2, sin(phi[1]) );
877 Rotations.set(2,0, -cos(phi[0]) *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2])));
878 Rotations.set(2,1, -sin(phi[0]) *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2])));
879 Rotations.set(2,2, cos(phi[1])*cos(phi[2]) );
880 }
881
882 // ... and put at new position
883 Inserter = (*iter)->getPosition();
884 if (DoRandomRotation)
885 Inserter *= Rotations;
886 Inserter += AtomTranslations + FillerTranslations + CurrentPosition;
887
888 // check whether inserter is inside box
889 Inserter *= MInverse;
890 FillIt = true;
891 for (int i=0;i<NDIM;i++)
892 FillIt = FillIt && (Inserter[i] >= -MYEPSILON) && ((Inserter[i]-1.) <= MYEPSILON);
893 Inserter *= M;
894
895 // Check whether point is in- or outside
896 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
897 // get linked cell list
898 if (TesselStruct[(*ListRunner)] != NULL) {
899 const double distance = (TesselStruct[(*ListRunner)]->GetDistanceToSurface(Inserter, LCList[(*ListRunner)]));
900 FillIt = FillIt && (distance > boundary) && ((MaxDistance < 0) || (MaxDistance > distance));
901 }
902 }
903 // insert into Filling
904 if (FillIt) {
905 LOG(1, "INFO: Position at " << Inserter << " is outer point.");
906 // copy atom ...
907 CopyAtoms[(*iter)->getNr()] = (*iter)->clone();
908 (*CopyAtoms[(*iter)->getNr()]).setPosition(Inserter);
909 Filling->AddAtom(CopyAtoms[(*iter)->getNr()]);
910 LOG(1, "Filling atom " << **iter << ", translated to " << AtomTranslations << ", at final position is " << (CopyAtoms[(*iter)->getNr()]->getPosition()) << ".");
911 } else {
912 LOG(1, "INFO: Position at " << Inserter << " is inner point, within boundary or outside of MaxDistance.");
913 CopyAtoms[(*iter)->getNr()] = NULL;
914 continue;
915 }
916 }
917 // go through all bonds and add as well
918 for(molecule::iterator AtomRunner = filler->begin(); AtomRunner != filler->end(); ++AtomRunner) {
919 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
920 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
921 BondRunner != ListOfBonds.end();
922 ++BondRunner)
923 if ((*BondRunner)->leftatom == *AtomRunner) {
924 Binder = (*BondRunner);
925 if ((CopyAtoms[Binder->leftatom->getNr()] != NULL) && (CopyAtoms[Binder->rightatom->getNr()] != NULL)) {
926 LOG(3, "Adding Bond between " << *CopyAtoms[Binder->leftatom->getNr()] << " and " << *CopyAtoms[Binder->rightatom->getNr()]<< ".");
927 Filling->AddBond(CopyAtoms[Binder->leftatom->getNr()], CopyAtoms[Binder->rightatom->getNr()], Binder->getDegree());
928 }
929 }
930 }
931 }
932 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
933 delete LCList[*ListRunner];
934 delete TesselStruct[(*ListRunner)];
935 }
936};
937
938/** Rotates given molecule \a Filling and moves its atoms according to given
939 * \a RandomAtomDisplacement.
940 *
941 * Note that for rotation to be sensible, the molecule should be centered at
942 * the origin. This is not done here!
943 *
944 * \param &Filling molecule whose atoms to displace
945 * \param RandomAtomDisplacement magnitude of random displacement
946 * \param &Rotations 3D rotation matrix (or unity if no rotation desired)
947 */
948void RandomizeMoleculePositions(
949 molecule *&Filling,
950 double RandomAtomDisplacement,
951 RealSpaceMatrix &Rotations,
952 RandomNumberGenerator &random
953 )
954{
955 const double rng_min = random.min();
956 const double rng_max = random.max();
957
958 Vector AtomTranslations;
959 for(molecule::iterator miter = Filling->begin(); miter != Filling->end(); ++miter) {
960 Vector temp = (*miter)->getPosition();
961 temp *= Rotations;
962 (*miter)->setPosition(temp);
963 // create atomic random translation vector ...
964 for (int i=0;i<NDIM;i++)
965 AtomTranslations[i] = RandomAtomDisplacement*(random()/((rng_max-rng_min)/2.) - 1.);
966 (*miter)->setPosition((*miter)->getPosition() + AtomTranslations);
967 }
968}
969
970/** Removes all atoms of a molecule outside.
971 *
972 * If the molecule is empty, it is removed as well.
973 *
974 * @param Filling molecule whose atoms to check, removed if eventually left
975 * empty.
976 * @return true - atoms had to be removed, false - no atoms have been removed
977 */
978bool RemoveAtomsOutsideDomain(molecule *&Filling)
979{
980 bool status = false;
981 Box &Domain = World::getInstance().getDomain();
982 // check if all is still inside domain
983 for(molecule::iterator miter = Filling->begin(); miter != Filling->end(); ) {
984 // check whether each atom is inside box
985 if (!Domain.isInside((*miter)->getPosition())) {
986 status = true;
987 atom *Walker = *miter;
988 ++miter;
989 World::getInstance().destroyAtom(Walker);
990 } else {
991 ++miter;
992 }
993 }
994 if (Filling->empty()) {
995 LOG(0, "Removing molecule " << Filling->getName() << ", all atoms have been removed.");
996 World::getInstance().destroyMolecule(Filling);
997 Filling = NULL;
998 }
999 return status;
1000}
1001
1002/** Checks whether there are no atoms inside a sphere around \a CurrentPosition
1003 * except those atoms present in \a *filler.
1004 * If filler is NULL, then we just call LinkedCell_deprecated::GetPointsInsideSphere() and
1005 * check whether the return list is empty.
1006 * @param *filler
1007 * @param boundary
1008 * @param CurrentPosition
1009 */
1010bool isSpaceAroundPointVoid(
1011 LinkedCell_deprecated *LC,
1012 molecule *filler,
1013 const double boundary,
1014 Vector &CurrentPosition)
1015{
1016 size_t compareTo = 0;
1017 TesselPointSTLList* liste = LC->GetPointsInsideSphere(boundary == 0. ? MYEPSILON : boundary, &CurrentPosition);
1018 if (filler != NULL) {
1019 for (TesselPointSTLList::const_iterator iter = liste->begin();
1020 iter != liste->end();
1021 ++iter) {
1022 for (molecule::iterator miter = filler->begin();
1023 miter != filler->end();
1024 ++miter) {
1025 if (*iter == *miter)
1026 ++compareTo;
1027 }
1028 }
1029 }
1030 const bool result = (liste->size() == compareTo);
1031 if (!result) {
1032 LOG(0, "Skipping because of the following atoms:");
1033 for (TesselPointSTLList::const_iterator iter = liste->begin();
1034 iter != liste->end();
1035 ++iter) {
1036 LOG(0, **iter);
1037 }
1038 }
1039 delete(liste);
1040 return result;
1041}
1042
1043/** Sets given 3x3 matrix to a random rotation matrix.
1044 *
1045 * @param a matrix to set
1046 */
1047inline void setRandomRotation(RealSpaceMatrix &a)
1048{
1049 double phi[NDIM];
1050 RandomNumberGenerator &random = RandomNumberGeneratorFactory::getInstance().makeRandomNumberGenerator();
1051 const double rng_min = random.min();
1052 const double rng_max = random.max();
1053
1054 for (int i=0;i<NDIM;i++) {
1055 phi[i] = (random()/(rng_max-rng_min))*(2.*M_PI);
1056 LOG(4, "DEBUG: Random angle is " << phi[i] << ".");
1057 }
1058
1059 a.setRotation(phi);
1060}
1061
1062/** Fills the empty space of the simulation box with water.
1063 * \param *filler molecule which the box is to be filled with
1064 * \param configuration contains box dimensions
1065 * \param distance[NDIM] distance between filling molecules in each direction
1066 * \param boundary length of boundary zone between molecule and filling molecules
1067 * \param RandAtomDisplacement maximum distance for random displacement per atom
1068 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
1069 * \param MinDistance minimum distance to boundary of domain and present molecules
1070 * \param DoRandomRotation true - do random rotations, false - don't
1071 */
1072void FillVoidWithMolecule(
1073 molecule *&filler,
1074 config &configuration,
1075 const double distance[NDIM],
1076 const double boundary,
1077 const double RandomAtomDisplacement,
1078 const double RandomMolDisplacement,
1079 const double MinDistance,
1080 const bool DoRandomRotation
1081 )
1082{
1083 //Info FunctionInfo(__func__);
1084 molecule *Filling = NULL;
1085 Vector CurrentPosition;
1086 int N[NDIM];
1087 int n[NDIM];
1088 const RealSpaceMatrix &M = World::getInstance().getDomain().getM();
1089 RealSpaceMatrix Rotations;
1090 const RealSpaceMatrix &MInverse = World::getInstance().getDomain().getMinv();
1091 Vector FillerTranslations;
1092 Vector FillerDistance;
1093 Vector Inserter;
1094 double FillIt = false;
1095 Vector firstInserter;
1096 bool firstInsertion = true;
1097 const Box &Domain = World::getInstance().getDomain();
1098 map<molecule *, LinkedCell_deprecated *> LCList;
1099 std::vector<molecule *> List = World::getInstance().getAllMolecules();
1100 MoleculeListClass *MolList = World::getInstance().getMolecules();
1101
1102 for (std::vector<molecule *>::iterator ListRunner = List.begin(); ListRunner != List.end(); ListRunner++)
1103 if ((*ListRunner)->getAtomCount() > 0) {
1104 LOG(1, "Pre-creating linked cell lists for molecule " << *ListRunner << ".");
1105 PointCloudAdaptor< molecule > cloud(*ListRunner, (*ListRunner)->name);
1106 LCList[(*ListRunner)] = new LinkedCell_deprecated(cloud, 10.); // get linked cell list
1107 }
1108
1109 // Center filler at its center of gravity
1110 const Vector gravity = filler->DetermineCenterOfGravity();
1111 filler->CenterAtVector(gravity);
1112 //const int FillerCount = filler->getAtomCount();
1113 LOG(2, "INFO: Filler molecule has the following bonds:");
1114 for(molecule::iterator AtomRunner = filler->begin(); AtomRunner != filler->end(); ++AtomRunner) {
1115 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
1116 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
1117 BondRunner != ListOfBonds.end();
1118 ++BondRunner)
1119 if ((*BondRunner)->leftatom == *AtomRunner)
1120 LOG(2, " " << *(*BondRunner));
1121 }
1122
1123 // calculate filler grid in [0,1]^3
1124 FillerDistance = MInverse * Vector(distance[0], distance[1], distance[2]);
1125 for(int i=0;i<NDIM;i++)
1126 N[i] = (int) ceil(1./FillerDistance[i]);
1127 LOG(1, "INFO: Grid steps are " << N[0] << ", " << N[1] << ", " << N[2] << ".");
1128
1129 // initialize seed of random number generator to current time
1130 RandomNumberGenerator &random = RandomNumberGeneratorFactory::getInstance().makeRandomNumberGenerator();
1131 const double rng_min = random.min();
1132 const double rng_max = random.max();
1133 //srand ( time(NULL) );
1134
1135 // go over [0,1]^3 filler grid
1136 for (n[0] = 0; n[0] < N[0]; n[0]++)
1137 for (n[1] = 0; n[1] < N[1]; n[1]++)
1138 for (n[2] = 0; n[2] < N[2]; n[2]++) {
1139 // calculate position of current grid vector in untransformed box
1140 CurrentPosition = M * Vector((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
1141 // create molecule random translation vector ...
1142 for (int i=0;i<NDIM;i++) // have the random values [-1,1]*RandomMolDisplacement
1143 FillerTranslations[i] = RandomMolDisplacement*(random()/((rng_max-rng_min)/2.) - 1.);
1144 LOG(2, "INFO: Current Position is " << CurrentPosition << "+" << FillerTranslations << ".");
1145
1146 // ... and rotation matrix
1147 if (DoRandomRotation)
1148 setRandomRotation(Rotations);
1149 else
1150 Rotations.setIdentity();
1151
1152
1153 // Check whether there is anything too close by and whether atom is outside of domain
1154 FillIt = true;
1155 for (std::map<molecule *, LinkedCell_deprecated *>::iterator ListRunner = LCList.begin(); ListRunner != LCList.end(); ++ListRunner) {
1156 FillIt = FillIt && isSpaceAroundPointVoid(
1157 ListRunner->second,
1158 (firstInsertion ? filler : NULL),
1159 boundary,
1160 CurrentPosition);
1161 FillIt = FillIt && (Domain.isValid(CurrentPosition))
1162 && ((Domain.DistanceToBoundary(CurrentPosition) - MinDistance) > -MYEPSILON);
1163 if (!FillIt)
1164 break;
1165 }
1166
1167 // insert into Filling
1168 if (FillIt) {
1169 Inserter = CurrentPosition + FillerTranslations;
1170 LOG(1, "INFO: Position at " << Inserter << " is void point.");
1171 // fill!
1172 Filling = filler->CopyMolecule();
1173 RandomizeMoleculePositions(Filling, RandomAtomDisplacement, Rotations, random);
1174 // translation
1175 Filling->Translate(Inserter);
1176 // remove out-of-bounds atoms
1177 const bool status = RemoveAtomsOutsideDomain(Filling);
1178 if ((firstInsertion) && (!status)) { // no atom has been removed
1179 // remove copied atoms and molecule again
1180 Filling->removeAtomsinMolecule();
1181 World::getInstance().destroyMolecule(Filling);
1182 // and mark is final filler position
1183 Filling = filler;
1184 firstInsertion = false;
1185 firstInserter = Inserter;
1186 } else {
1187 // TODO: Remove when World has no MoleculeListClass anymore
1188 if (Filling)
1189 MolList->insert(Filling);
1190 }
1191 } else {
1192 LOG(1, "INFO: Position at " << Inserter << " is non-void point, within boundary or outside of MaxDistance.");
1193 continue;
1194 }
1195 }
1196
1197 // have we inserted any molecules?
1198 if (firstInsertion) {
1199 // If not remove filler
1200 for(molecule::iterator miter = filler->begin(); !filler->empty(); miter = filler->begin()) {
1201 atom *Walker = *miter;
1202 World::getInstance().destroyAtom(Walker);
1203 }
1204 World::getInstance().destroyMolecule(filler);
1205 } else {
1206 // otherwise translate and randomize to final position
1207 if (DoRandomRotation)
1208 setRandomRotation(Rotations);
1209 else
1210 Rotations.setIdentity();
1211 RandomizeMoleculePositions(filler, RandomAtomDisplacement, Rotations, random);
1212 // translation
1213 filler->Translate(firstInserter);
1214 // remove out-of-bounds atoms
1215 RemoveAtomsOutsideDomain(filler);
1216 }
1217
1218 LOG(0, MolList->ListOfMolecules.size() << " molecules have been inserted.");
1219
1220 for (std::map<molecule *, LinkedCell_deprecated *>::iterator ListRunner = LCList.begin(); !LCList.empty(); ListRunner = LCList.begin()) {
1221 delete ListRunner->second;
1222 LCList.erase(ListRunner);
1223 }
1224};
1225
1226
1227/** Fills the empty space around other molecules' surface of the simulation box with a filler.
1228 *
1229 * Note that we use \a FindNonConvexBorder to determine the surface of the found molecules.
1230 * There, we use a radius of twice the given \a boundary.
1231 *
1232 * \param *out output stream for debugging
1233 * \param *List list of molecules already present in box
1234 * \param *TesselStruct contains tesselated surface
1235 * \param *filler molecule which the box is to be filled with
1236 * \param configuration contains box dimensions
1237 * \param MaxSurfaceDistance fills in molecules only up to this distance (set to -1 if whole of the domain)
1238 * \param distance[NDIM] distance between filling molecules in each direction
1239 * \param boundary length of boundary zone between molecule and filling molecules
1240 * \param MinDistance distance to boundary of domain which is not filled
1241 * \param RandAtomDisplacement maximum distance for random displacement per atom
1242 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
1243 * \param DoRandomRotation true - do random rotations, false - don't
1244 */
1245void FillBoxWithMolecule(
1246 MoleculeListClass *MolList,
1247 molecule *filler,
1248 config &configuration,
1249 const double MaxSurfaceDistance,
1250 const double distance[NDIM],
1251 const double boundary,
1252 const double MinDistance,
1253 const double RandomAtomDisplacement,
1254 const double RandomMolDisplacement,
1255 const bool DoRandomRotation)
1256{
1257 //Info FunctionInfo(__func__);
1258 molecule *Filling = NULL;
1259 Vector CurrentPosition;
1260 int N[NDIM];
1261 int n[NDIM];
1262 const RealSpaceMatrix &M = World::getInstance().getDomain().getM();
1263 RealSpaceMatrix Rotations;
1264 const RealSpaceMatrix &MInverse = World::getInstance().getDomain().getMinv();
1265 Vector FillerTranslations;
1266 Vector FillerDistance;
1267 Vector Inserter;
1268 double FillIt = false;
1269 Vector firstInserter;
1270 bool firstInsertion = true;
1271 const Box &Domain = World::getInstance().getDomain();
1272 map<molecule *, LinkedCell_deprecated *> LCList;
1273 std::vector<molecule *> List = World::getInstance().getAllMolecules();
1274 map<molecule *, Tesselation *> TesselStruct;
1275
1276 for (MoleculeList::iterator ListRunner = MolList->ListOfMolecules.begin(); ListRunner != MolList->ListOfMolecules.end(); ListRunner++)
1277 if ((*ListRunner)->getAtomCount() > 0) {
1278 LOG(1, "Pre-creating linked cell lists for molecule " << *ListRunner << ".");
1279 PointCloudAdaptor< molecule > cloud(*ListRunner, (*ListRunner)->name);
1280 LCList[(*ListRunner)] = new LinkedCell_deprecated(cloud, 4.*boundary); // get linked cell list
1281 LOG(1, "Pre-creating tesselation for molecule " << *ListRunner << ".");
1282 TesselStruct[(*ListRunner)] = NULL;
1283 FindNonConvexBorder((*ListRunner), TesselStruct[(*ListRunner)], (const LinkedCell_deprecated *&)LCList[(*ListRunner)], 2.*boundary, NULL);
1284 }
1285
1286 // Center filler at origin
1287 filler->CenterEdge();
1288// const int FillerCount = filler->getAtomCount();
1289 LOG(2, "INFO: Filler molecule has the following bonds:");
1290 for(molecule::iterator AtomRunner = filler->begin(); AtomRunner != filler->end(); ++AtomRunner) {
1291 const BondList& ListOfBonds = (*AtomRunner)->getListOfBonds();
1292 for(BondList::const_iterator BondRunner = ListOfBonds.begin();
1293 BondRunner != ListOfBonds.end();
1294 ++BondRunner) {
1295 if ((*BondRunner)->leftatom == *AtomRunner)
1296 LOG(2, " " << *(*BondRunner));
1297 }
1298 }
1299
1300// atom * CopyAtoms[FillerCount];
1301
1302 setVerbosity(4);
1303
1304 // calculate filler grid in [0,1]^3
1305 FillerDistance = MInverse * Vector(distance[0], distance[1], distance[2]);
1306 for(int i=0;i<NDIM;i++)
1307 N[i] = (int) ceil(1./FillerDistance[i]);
1308 LOG(1, "INFO: Grid steps are " << N[0] << ", " << N[1] << ", " << N[2] << ".");
1309
1310 // initialize seed of random number generator to current time
1311 RandomNumberGenerator &random = RandomNumberGeneratorFactory::getInstance().makeRandomNumberGenerator();
1312 const double rng_min = random.min();
1313 const double rng_max = random.max();
1314 //srand ( time(NULL) );
1315
1316 // go over [0,1]^3 filler grid
1317 for (n[0] = 0; n[0] < N[0]; n[0]++)
1318 for (n[1] = 0; n[1] < N[1]; n[1]++)
1319 for (n[2] = 0; n[2] < N[2]; n[2]++) {
1320 // calculate position of current grid vector in untransformed box
1321 CurrentPosition = M * Vector((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
1322 // create molecule random translation vector ...
1323 for (int i=0;i<NDIM;i++)
1324 FillerTranslations[i] = RandomMolDisplacement*(random()/((rng_max-rng_min)/2.) - 1.);
1325 LOG(1, "INFO: Current Position is " << CurrentPosition << "+" << FillerTranslations << ".");
1326
1327 // ... and rotation matrix
1328 if (DoRandomRotation)
1329 setRandomRotation(Rotations);
1330 else
1331 Rotations.setIdentity();
1332
1333
1334 // Check whether there is anything too close by and whether atom is outside of domain
1335 FillIt = true;
1336 for (std::map<molecule *, LinkedCell_deprecated *>::iterator ListRunner = LCList.begin(); ListRunner != LCList.end(); ++ListRunner) {
1337 // check whether its void
1338 FillIt = FillIt && isSpaceAroundPointVoid(
1339 ListRunner->second,
1340 (firstInsertion ? filler : NULL),
1341 boundary,
1342 CurrentPosition);
1343 if (!FillIt) {
1344 LOG(2, "REJECT: Position at " << Inserter << " is non-void.");
1345 break;
1346 }
1347 // check whether inside domain
1348 FillIt = FillIt && (Domain.isValid(CurrentPosition));
1349 if (!FillIt) {
1350 LOG(2, "REJECT: Position at " << CurrentPosition << " is "
1351 << distance << ", hence outside of domain.");
1352 break;
1353 }
1354 // check minimum distance to boundary
1355 const double distance = (Domain.DistanceToBoundary(CurrentPosition) - MinDistance);
1356 FillIt = FillIt && (distance > -MYEPSILON);
1357 if (!FillIt) {
1358 LOG(2, "REJECT: Position at " << CurrentPosition << " is " << distance << ", less than "
1359 << MinDistance << " hence, too close to boundary.");
1360 break;
1361 }
1362 }
1363 // Check whether point is in- or outside of tesselations
1364 if (FillIt) {
1365 for (MoleculeList::iterator ListRunner = MolList->ListOfMolecules.begin(); ListRunner != MolList->ListOfMolecules.end(); ListRunner++) {
1366 // get linked cell list
1367 if (TesselStruct[(*ListRunner)] != NULL) {
1368 const double distance = (TesselStruct[(*ListRunner)]->GetDistanceToSurface(Inserter, LCList[(*ListRunner)]));
1369 LOG(2, "INFO: Distance to surface is " << distance << ".");
1370 FillIt = FillIt && ((distance == -1.) || (distance > boundary)) && ((MaxSurfaceDistance < 0) || (MaxSurfaceDistance > distance));
1371 if (!FillIt) {
1372 LOG(2, "REJECT: Position at " << CurrentPosition << " is in distance of " << distance
1373 << " to a surface, less than " << MaxSurfaceDistance << " hence, too close.");
1374 break;
1375 }
1376 }
1377 }
1378 }
1379
1380 // insert into Filling
1381 if (FillIt) {
1382 Inserter = CurrentPosition + FillerTranslations;
1383 LOG(2, "ACCEPT: Position at " << CurrentPosition << " is void point.");
1384 // fill!
1385 Filling = filler->CopyMolecule();
1386 RandomizeMoleculePositions(Filling, RandomAtomDisplacement, Rotations, random);
1387 // translation
1388 Filling->Translate(Inserter);
1389 // remove out-of-bounds atoms
1390 const bool status = RemoveAtomsOutsideDomain(Filling);
1391 if ((firstInsertion) && (!status)) { // no atom has been removed
1392 // remove copied atoms and molecule again
1393 Filling->removeAtomsinMolecule();
1394 World::getInstance().destroyMolecule(Filling);
1395 // and mark is final filler position
1396 Filling = filler;
1397 firstInsertion = false;
1398 firstInserter = Inserter;
1399 } else {
1400 // TODO: Remove when World has no MoleculeListClass anymore
1401 if (Filling)
1402 MolList->insert(Filling);
1403 }
1404 } else {
1405 LOG(2, "REJECT: Position at " << CurrentPosition << " is non-void point, within boundary or outside of MaxSurfaceDistance.");
1406 continue;
1407 }
1408 }
1409
1410 // have we inserted any molecules?
1411 if (firstInsertion) {
1412 // If not remove filler
1413 for(molecule::iterator miter = filler->begin(); !filler->empty(); miter = filler->begin()) {
1414 atom *Walker = *miter;
1415 World::getInstance().destroyAtom(Walker);
1416 }
1417 World::getInstance().destroyMolecule(filler);
1418 } else {
1419 // otherwise translate and randomize to final position
1420 if (DoRandomRotation)
1421 setRandomRotation(Rotations);
1422 else
1423 Rotations.setIdentity();
1424 RandomizeMoleculePositions(filler, RandomAtomDisplacement, Rotations, random);
1425 // translation
1426 filler->Translate(firstInserter);
1427 // remove out-of-bounds atoms
1428 RemoveAtomsOutsideDomain(filler);
1429 }
1430
1431 LOG(0, MolList->ListOfMolecules.size() << " molecules have been inserted.");
1432
1433 for (std::map<molecule *, LinkedCell_deprecated *>::iterator ListRunner = LCList.begin(); !LCList.empty(); ListRunner = LCList.begin()) {
1434 delete ListRunner->second;
1435 LCList.erase(ListRunner);
1436 }
1437};
1438
1439/** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
1440 * \param *out output stream for debugging
1441 * \param *mol molecule structure with Atom's and Bond's
1442 * \param *&TesselStruct Tesselation filled with points, lines and triangles on boundary on return
1443 * \param *&LCList atoms in LinkedCell_deprecated list
1444 * \param RADIUS radius of the virtual sphere
1445 * \param *filename filename prefix for output of vertex data
1446 * \return true - tesselation successful, false - tesselation failed
1447 */
1448bool FindNonConvexBorder(molecule* const mol, Tesselation *&TesselStruct, const LinkedCell_deprecated *&LCList, const double RADIUS, const char *filename = NULL)
1449{
1450 //Info FunctionInfo(__func__);
1451 bool freeLC = false;
1452 bool status = false;
1453 CandidateForTesselation *baseline = NULL;
1454 bool OneLoopWithoutSuccessFlag = true; // marks whether we went once through all baselines without finding any without two triangles
1455// bool TesselationFailFlag = false;
1456
1457 mol->getAtomCount();
1458
1459 if (TesselStruct == NULL) {
1460 LOG(1, "Allocating Tesselation struct ...");
1461 TesselStruct= new Tesselation;
1462 } else {
1463 delete(TesselStruct);
1464 LOG(1, "Re-Allocating Tesselation struct ...");
1465 TesselStruct = new Tesselation;
1466 }
1467
1468 // initialise Linked Cell
1469 PointCloudAdaptor< molecule > cloud(mol, mol->name);
1470 if (LCList == NULL) {
1471 LCList = new LinkedCell_deprecated(cloud, 2.*RADIUS);
1472 freeLC = true;
1473 }
1474
1475 // 1. get starting triangle
1476 if (!TesselStruct->FindStartingTriangle(RADIUS, LCList)) {
1477 ELOG(0, "No valid starting triangle found.");
1478 //performCriticalExit();
1479 }
1480 if (filename != NULL) {
1481 if ((DoSingleStepOutput && ((TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
1482 TesselStruct->Output(filename, cloud);
1483 }
1484 }
1485
1486 // 2. expand from there
1487 while ((!TesselStruct->OpenLines.empty()) && (OneLoopWithoutSuccessFlag)) {
1488 (cerr << "There are " << TesselStruct->TrianglesOnBoundary.size() << " triangles and " << TesselStruct->OpenLines.size() << " open lines to scan for candidates." << endl);
1489 // 2a. print OpenLines without candidates
1490 LOG(1, "There are the following open lines to scan for a candidates:");
1491 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
1492 if (Runner->second->pointlist.empty())
1493 LOG(1, " " << *(Runner->second));
1494
1495 // 2b. find best candidate for each OpenLine
1496 const bool TesselationFailFlag = TesselStruct->FindCandidatesforOpenLines(RADIUS, LCList);
1497 ASSERT( TesselationFailFlag,
1498 "FindNonConvexBorder() - at least one open line without candidate exists.");
1499
1500 // 2c. print OpenLines with candidates again
1501 LOG(1, "There are " << TesselStruct->OpenLines.size() << " open lines to scan for the best candidates:");
1502 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
1503 LOG(1, " " << *(Runner->second));
1504
1505 // 2d. search for smallest ShortestAngle among all candidates
1506 double ShortestAngle = 4.*M_PI;
1507 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++) {
1508 if (Runner->second->ShortestAngle < ShortestAngle) {
1509 baseline = Runner->second;
1510 ShortestAngle = baseline->ShortestAngle;
1511 LOG(1, "New best candidate is " << *baseline->BaseLine << " with point " << *(*baseline->pointlist.begin()) << " and angle " << baseline->ShortestAngle);
1512 }
1513 }
1514 // 2e. if we found one, add candidate
1515 if ((ShortestAngle == 4.*M_PI) || (baseline->pointlist.empty()))
1516 OneLoopWithoutSuccessFlag = false;
1517 else {
1518 TesselStruct->AddCandidatePolygon(*baseline, RADIUS, LCList);
1519 }
1520
1521 // 2f. write temporary envelope
1522 if (filename != NULL) {
1523 if ((DoSingleStepOutput && ((TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
1524 TesselStruct->Output(filename, cloud);
1525 }
1526 }
1527 }
1528// // check envelope for consistency
1529// status = CheckListOfBaselines(TesselStruct);
1530//
1531// // look whether all points are inside of the convex envelope, otherwise add them via degenerated triangles
1532// //->InsertStraddlingPoints(mol, LCList);
1533// for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
1534// class TesselPoint *Runner = NULL;
1535// Runner = *iter;
1536// LOG(1, "Checking on " << Runner->Name << " ... ");
1537// if (!->IsInnerPoint(Runner, LCList)) {
1538// LOG(2, Runner->Name << " is outside of envelope, adding via degenerated triangles.");
1539// ->AddBoundaryPointByDegeneratedTriangle(Runner, LCList);
1540// } else {
1541// LOG(2, Runner->Name << " is inside of or on envelope.");
1542// }
1543// }
1544
1545// // Purges surplus triangles.
1546// TesselStruct->RemoveDegeneratedTriangles();
1547//
1548// // check envelope for consistency
1549// status = CheckListOfBaselines(TesselStruct);
1550
1551 cout << "before correction" << endl;
1552
1553 // store before correction
1554 StoreTrianglesinFile(mol, TesselStruct, filename, "");
1555
1556// // correct degenerated polygons
1557// TesselStruct->CorrectAllDegeneratedPolygons();
1558//
1559 // check envelope for consistency
1560 status = CheckListOfBaselines(TesselStruct);
1561
1562 // write final envelope
1563 CalculateConcavityPerBoundaryPoint(TesselStruct);
1564 cout << "after correction" << endl;
1565 StoreTrianglesinFile(mol, TesselStruct, filename, "");
1566
1567 if (freeLC)
1568 delete(LCList);
1569
1570 return status;
1571};
1572
1573
1574/** Finds a hole of sufficient size in \a *mols to embed \a *srcmol into it.
1575 * \param *out output stream for debugging
1576 * \param *mols molecules in the domain to embed in between
1577 * \param *srcmol embedding molecule
1578 * \return *Vector new center of \a *srcmol for embedding relative to \a this
1579 */
1580Vector* FindEmbeddingHole(MoleculeListClass *mols, molecule *srcmol)
1581{
1582 //Info FunctionInfo(__func__);
1583 Vector *Center = new Vector;
1584 Center->Zero();
1585 // calculate volume/shape of \a *srcmol
1586
1587 // find embedding holes
1588
1589 // if more than one, let user choose
1590
1591 // return embedding center
1592 return Center;
1593};
1594
Note: See TracBrowser for help on using the repository browser.