source: src/Tesselation/boundary.cpp@ 6da9e9

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 Candidate_v1.7.0 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 6da9e9 was b8d215, checked in by Frederik Heber <heber@…>, 11 years ago

Changed some verbosities in Tesselation code.

  • Property mode set to 100644
File size: 34.8 KB
RevLine 
[bcf653]1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
[0aa122]4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
[5aaa43]5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
[94d5ac6]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/>.
[bcf653]22 */
23
[f66195]24/** \file boundary.cpp
[edb93c]25 *
26 * Implementations and super-function for envelopes
[2319ed]27 */
28
[bf3817]29// include config.h
30#ifdef HAVE_CONFIG_H
31#include <config.h>
32#endif
33
[ad011c]34#include "CodePatterns/MemDebug.hpp"
[112b09]35
[6f0841]36#include "Atom/atom.hpp"
[129204]37#include "Bond/bond.hpp"
[8eb17a]38#include "boundary.hpp"
[34c43a]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"
[f66195]47#include "config.hpp"
[3bdb6d]48#include "Element/element.hpp"
[34c43a]49#include "LinearAlgebra/Plane.hpp"
50#include "LinearAlgebra/RealSpaceMatrix.hpp"
[53c7fc]51#include "LinkedCell/linkedcell.hpp"
52#include "LinkedCell/PointCloudAdaptor.hpp"
[f66195]53#include "molecule.hpp"
[42127c]54#include "MoleculeListClass.hpp"
[34c43a]55#include "RandomNumbers/RandomNumberGeneratorFactory.hpp"
56#include "RandomNumbers/RandomNumberGenerator.hpp"
[f66195]57#include "tesselation.hpp"
58#include "tesselationhelpers.hpp"
[b34306]59#include "World.hpp"
[2319ed]60
[986ed3]61#include <iostream>
[36166d]62#include <iomanip>
63
[357fba]64#include<gsl/gsl_poly.h>
[d6eb80]65#include<time.h>
[2319ed]66
[357fba]67// ========================================== F U N C T I O N S =================================
[2319ed]68
69
[357fba]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
[2319ed]72 * \param *out output stream for debugging
[357fba]73 * \param *BoundaryPoints NDIM set of boundary points defining the convex envelope on each projected plane
74 * \param *mol molecule structure representing the cluster
[776b64]75 * \param *&TesselStruct Tesselation structure with triangles
[357fba]76 * \param IsAngstroem whether we have angstroem or atomic units
77 * \return NDIM array of the diameters
[e4ea46]78 */
[e138de]79double *GetDiametersOfCluster(const Boundaries *BoundaryPtr, const molecule *mol, Tesselation *&TesselStruct, const bool IsAngstroem)
[caf5d6]80{
[ce7bfd]81 //Info FunctionInfo(__func__);
[357fba]82 // get points on boundary of NULL was given as parameter
83 bool BoundaryFreeFlag = false;
[ad37ab]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;
[776b64]92 Boundaries::const_iterator Neighbour;
93 Boundaries::const_iterator OtherNeighbour;
[ad37ab]94 double *GreatestDiameter = new double[NDIM];
95
[776b64]96 const Boundaries *BoundaryPoints;
97 if (BoundaryPtr == NULL) {
[357fba]98 BoundaryFreeFlag = true;
[e138de]99 BoundaryPoints = GetBoundaryPoints(mol, TesselStruct);
[86234b]100 } else {
[776b64]101 BoundaryPoints = BoundaryPtr;
[47d041]102 LOG(0, "Using given boundary points set.");
[86234b]103 }
[357fba]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
[47d041]109 //LOG(1, "Current axis is " << axis << ".");
[357fba]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;
[47d041]114 //LOG(1, "Current component is " << component << ", Othercomponent is " << Othercomponent << ".");
[776b64]115 for (Boundaries::const_iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
[47d041]116 //LOG(1, "Current runner is " << *(runner->second.second) << ".");
[357fba]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();
[d74077]122 DistanceVector = (runner->second.second->getPosition()) - (Neighbour->second.second->getPosition());
[776b64]123 do { // seek for neighbour pair where it flips
[0a4f7f]124 OldComponent = DistanceVector[Othercomponent];
[357fba]125 Neighbour++;
126 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
127 Neighbour = BoundaryPoints[axis].begin();
[d74077]128 DistanceVector = (runner->second.second->getPosition()) - (Neighbour->second.second->getPosition());
[47d041]129 //LOG(2, "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << ".");
[776b64]130 } while ((runner != Neighbour) && (fabs(OldComponent / fabs(
[0a4f7f]131 OldComponent) - DistanceVector[Othercomponent] / fabs(
132 DistanceVector[Othercomponent])) < MYEPSILON)); // as long as sign does not flip
[776b64]133 if (runner != Neighbour) {
[357fba]134 OtherNeighbour = Neighbour;
135 if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around
136 OtherNeighbour = BoundaryPoints[axis].end();
137 OtherNeighbour--;
[47d041]138 //LOG(1, "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << ".");
[357fba]139 // now we have found the pair: Neighbour and OtherNeighbour
[d74077]140 OtherVector = (runner->second.second->getPosition()) - (OtherNeighbour->second.second->getPosition());
[47d041]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] << ".");
[357fba]143 // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour
[0a4f7f]144 w1 = fabs(OtherVector[Othercomponent]);
145 w2 = fabs(DistanceVector[Othercomponent]);
146 tmp = fabs((w1 * DistanceVector[component] + w2
147 * OtherVector[component]) / (w1 + w2));
[357fba]148 // mark if it has greater diameter
[47d041]149 //LOG(1, "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << ".");
[357fba]150 GreatestDiameter[component] = (GreatestDiameter[component]
151 > tmp) ? GreatestDiameter[component] : tmp;
152 } //else
[47d041]153 //LOG(1, "Saw no sign flip, probably top or bottom node.");
[3d919e]154 }
155 }
156 }
[47d041]157 LOG(0, "RESULT: The biggest diameters are "
[357fba]158 << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and "
159 << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom"
[47d041]160 : "atomiclength") << ".");
[03648b]161
[357fba]162 // free reference lists
163 if (BoundaryFreeFlag)
164 delete[] (BoundaryPoints);
[e4ea46]165
[357fba]166 return GreatestDiameter;
[e4ea46]167}
168;
[03648b]169
[042f82]170
[357fba]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
[776b64]177 * \param *&TesselStruct pointer to Tesselation structure
[e4ea46]178 */
[e138de]179Boundaries *GetBoundaryPoints(const molecule *mol, Tesselation *&TesselStruct)
[caf5d6]180{
[ce7bfd]181 //Info FunctionInfo(__func__);
[357fba]182 PointMap PointsOnBoundary;
183 LineMap LinesOnBoundary;
184 TriangleMap TrianglesOnBoundary;
[833b15]185 Vector MolCenter = mol->DetermineCenterOfAll();
[357fba]186 Vector helper;
[ad37ab]187 BoundariesTestPair BoundaryTestPair;
188 Vector AxisVector;
189 Vector AngleReferenceVector;
190 Vector AngleReferenceNormalVector;
191 Vector ProjectedVector;
[5309ba]192 Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, Nr)
[ad37ab]193 double angle = 0.;
[042f82]194
[357fba]195 // 3a. Go through every axis
196 for (int axis = 0; axis < NDIM; axis++) {
197 AxisVector.Zero();
198 AngleReferenceVector.Zero();
199 AngleReferenceNormalVector.Zero();
[0a4f7f]200 AxisVector[axis] = 1.;
201 AngleReferenceVector[(axis + 1) % NDIM] = 1.;
202 AngleReferenceNormalVector[(axis + 2) % NDIM] = 1.;
[042f82]203
[47d041]204 LOG(1, "Axisvector is " << AxisVector << " and AngleReferenceVector is " << AngleReferenceVector << ", and AngleReferenceNormalVector is " << AngleReferenceNormalVector << ".");
[042f82]205
[357fba]206 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
[59fff1]207 // Boundaries stores non-const TesselPoint ref, hence we need iterator here
208 for (molecule::iterator iter = mol->begin(); iter != mol->end(); ++iter) {
[833b15]209 ProjectedVector = (*iter)->getPosition() - (MolCenter);
[273382]210 ProjectedVector.ProjectOntoPlane(AxisVector);
[042f82]211
[357fba]212 // correct for negative side
[776b64]213 const double radius = ProjectedVector.NormSquared();
[357fba]214 if (fabs(radius) > MYEPSILON)
[273382]215 angle = ProjectedVector.Angle(AngleReferenceVector);
[357fba]216 else
217 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
[042f82]218
[47d041]219 //LOG(1, "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << ".");
[273382]220 if (ProjectedVector.ScalarProduct(AngleReferenceNormalVector) > 0) {
[357fba]221 angle = 2. * M_PI - angle;
222 }
[47d041]223 LOG(1, "Inserting " << **iter << ": (r, alpha) = (" << radius << "," << angle << "): " << ProjectedVector);
[6b5657]224 BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle, TesselPointDistancePair (radius, (*iter))));
[357fba]225 if (!BoundaryTestPair.second) { // same point exists, check first r, then distance of original vectors to center of gravity
[47d041]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);
[776b64]229 const double ProjectedVectorNorm = ProjectedVector.NormSquared();
230 if ((ProjectedVectorNorm - BoundaryTestPair.first->second.first) > MYEPSILON) {
231 BoundaryTestPair.first->second.first = ProjectedVectorNorm;
[9879f6]232 BoundaryTestPair.first->second.second = (*iter);
[47d041]233 LOG(2, "Keeping new vector due to larger projected distance " << ProjectedVectorNorm << ".");
[776b64]234 } else if (fabs(ProjectedVectorNorm - BoundaryTestPair.first->second.first) < MYEPSILON) {
[833b15]235 helper = (*iter)->getPosition() - (MolCenter);
[776b64]236 const double oldhelperNorm = helper.NormSquared();
[833b15]237 helper = BoundaryTestPair.first->second.second->getPosition() - (MolCenter);
[776b64]238 if (helper.NormSquared() < oldhelperNorm) {
[9879f6]239 BoundaryTestPair.first->second.second = (*iter);
[47d041]240 LOG(2, "Keeping new vector due to larger distance to molecule center " << helper.NormSquared() << ".");
[357fba]241 } else {
[47d041]242 LOG(2, "Keeping present vector due to larger distance to molecule center " << oldhelperNorm << ".");
[357fba]243 }
244 } else {
[47d041]245 LOG(2, "Keeping present vector due to larger projected distance " << ProjectedVectorNorm << ".");
[357fba]246 }
[018741]247 }
[3d919e]248 }
[357fba]249 // printing all inserted for debugging
250 // {
[47d041]251 // std::stringstream output;
252 // output << "Printing list of candidates for axis " << axis << " which we have inserted so far: ";
[357fba]253 // int i=0;
254 // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
255 // if (runner != BoundaryPoints[axis].begin())
[47d041]256 // output << ", " << i << ": " << *runner->second.second;
[357fba]257 // else
[47d041]258 // output << i << ": " << *runner->second.second;
[357fba]259 // i++;
260 // }
[47d041]261 // LOG(1, output.str());
[357fba]262 // }
263 // 3c. throw out points whose distance is less than the mean of left and right neighbours
264 bool flag = false;
[47d041]265 LOG(1, "Looking for candidates to kick out by convex condition ... ");
[357fba]266 do { // do as long as we still throw one out per round
267 flag = false;
[accebe]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++;
[357fba]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();
[accebe]284 LoopOnceDone = true;
[357fba]285 }
286 // check distance
[3d919e]287
[357fba]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;
[833b15]291 SideA = left->second.second->getPosition() - (MolCenter);
[273382]292 SideA.ProjectOntoPlane(AxisVector);
[47d041]293 // LOG(1, "SideA: " << SideA);
[3d919e]294
[833b15]295 SideB = right->second.second->getPosition() -(MolCenter);
[273382]296 SideB.ProjectOntoPlane(AxisVector);
[47d041]297 // LOG(1, "SideB: " << SideB);
[3d919e]298
[d74077]299 SideC = left->second.second->getPosition() - right->second.second->getPosition();
[273382]300 SideC.ProjectOntoPlane(AxisVector);
[47d041]301 // LOG(1, "SideC: " << SideC);
[3d919e]302
[833b15]303 SideH = runner->second.second->getPosition() -(MolCenter);
[273382]304 SideH.ProjectOntoPlane(AxisVector);
[47d041]305 // LOG(1, "SideH: " << SideH);
[3d919e]306
[357fba]307 // calculate each length
[ad37ab]308 const double a = SideA.Norm();
309 //const double b = SideB.Norm();
310 //const double c = SideC.Norm();
311 const double h = SideH.Norm();
[357fba]312 // calculate the angles
[273382]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);
[ad37ab]317 const double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.);
[47d041]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 << ".");
[357fba]320 if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance)) < MYEPSILON) && ((h - MinDistance)) < -MYEPSILON) {
321 // throw out point
[47d041]322 LOG(1, "Throwing out " << *runner->second.second << ".");
[357fba]323 BoundaryPoints[axis].erase(runner);
[accebe]324 runner = right;
[357fba]325 flag = true;
[3d919e]326 }
327 }
328 }
[357fba]329 } while (flag);
[3d919e]330 }
[357fba]331 return BoundaryPoints;
[6ac7ee]332};
333
[357fba]334/** Tesselates the convex boundary by finding all boundary points.
335 * \param *out output stream for debugging
[776b64]336 * \param *mol molecule structure with Atom's and Bond's.
[bdc91e]337 * \param *BoundaryPts set of boundary points to use or NULL
[357fba]338 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
[6bd7e0]339 * \param *LCList atoms in LinkedCell_deprecated list
[357fba]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.
[6ac7ee]342 */
[6bd7e0]343void FindConvexBorder(const molecule* mol, Boundaries *BoundaryPts, Tesselation *&TesselStruct, const LinkedCell_deprecated *LCList, const char *filename)
[6ac7ee]344{
[ce7bfd]345 //Info FunctionInfo(__func__);
[357fba]346 bool BoundaryFreeFlag = false;
347 Boundaries *BoundaryPoints = NULL;
[3d919e]348
[776b64]349 if (TesselStruct != NULL) // free if allocated
350 delete(TesselStruct);
351 TesselStruct = new class Tesselation;
[3d919e]352
[357fba]353 // 1. Find all points on the boundary
[bdc91e]354 if (BoundaryPts == NULL) {
355 BoundaryFreeFlag = true;
356 BoundaryPoints = GetBoundaryPoints(mol, TesselStruct);
[357fba]357 } else {
[bdc91e]358 BoundaryPoints = BoundaryPts;
[47d041]359 LOG(0, "Using given boundary points set.");
[3d919e]360 }
361
[357fba]362// printing all inserted for debugging
[47d041]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());
[a37350]376 }
[bdc91e]377 }
[3d919e]378
[357fba]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++)
[776b64]382 if (!TesselStruct->AddBoundaryPoint(runner->second.second, 0))
[47d041]383 LOG(2, "Point " << *(runner->second.second) << " is already present.");
[e4ea46]384
[47d041]385 LOG(0, "I found " << TesselStruct->PointsOnBoundaryCount << " points on the convex boundary.");
[357fba]386 // now we have the whole set of edge points in the BoundaryList
[018741]387
[357fba]388 // listing for debugging
[47d041]389 //if (DoLog(1)) {
390 // std::stringstream output;
391 // output << "Listing PointsOnBoundary:";
[357fba]392 // for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
[47d041]393 // output << " " << *runner->second;
[357fba]394 // }
[47d041]395 // LOG(1, output.str());
396 //}
[018741]397
[357fba]398 // 3a. guess starting triangle
[e138de]399 TesselStruct->GuessStartingTriangle();
[018741]400
[357fba]401 // 3b. go through all lines, that are not yet part of two triangles (only of one so far)
[caa06ef]402 PointCloudAdaptor< molecule > cloud(const_cast<molecule *>(mol), mol->name);
[34c43a]403 TesselStruct->TesselateOnBoundary(cloud);
[3d919e]404
[357fba]405 // 3c. check whether all atoms lay inside the boundary, if not, add to boundary points, segment triangle into three with the new point
[34c43a]406 if (!TesselStruct->InsertStraddlingPoints(cloud, LCList))
[47d041]407 ELOG(1, "Insertion of straddling points failed!");
[3d919e]408
[47d041]409 LOG(0, "I created " << TesselStruct->TrianglesOnBoundary.size() << " intermediate triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points.");
[ef0e6d]410
411 // 4. Store triangles in tecplot file
[d51975]412 StoreTrianglesinFile(mol, TesselStruct, filename, "_intermed");
[ef0e6d]413
[357fba]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
[ad37ab]415 bool AllConvex = true;
[093645]416 class BoundaryLineSet *line = NULL;
417 do {
418 AllConvex = true;
[776b64]419 for (LineMap::iterator LineRunner = TesselStruct->LinesOnBoundary.begin(); LineRunner != TesselStruct->LinesOnBoundary.end(); LineRunner++) {
[093645]420 line = LineRunner->second;
[47d041]421 LOG(1, "INFO: Current line is " << *line << ".");
[e138de]422 if (!line->CheckConvexityCriterion()) {
[47d041]423 LOG(1, "... line " << *line << " is concave, flipping it.");
[093645]424
425 // flip the line
[e138de]426 if (TesselStruct->PickFarthestofTwoBaselines(line) == 0.)
[47d041]427 ELOG(1, "Correction of concave baselines failed!");
[57066a]428 else {
[e138de]429 TesselStruct->FlipBaseline(line);
[47d041]430 LOG(1, "INFO: Correction of concave baselines worked.");
[accebe]431 LineRunner = TesselStruct->LinesOnBoundary.begin(); // LineRunner may have been erase if line was deleted from LinesOnBoundary
[57066a]432 }
[093645]433 }
434 }
435 } while (!AllConvex);
[3d919e]436
[ef0e6d]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)
[776b64]438// if (!TesselStruct->CorrectConcaveTesselPoints(out))
[47d041]439// ELOG(1, "Correction of concave tesselpoints failed!");
[ef0e6d]440
[47d041]441 LOG(0, "I created " << TesselStruct->TrianglesOnBoundary.size() << " triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points.");
[3d919e]442
[357fba]443 // 4. Store triangles in tecplot file
[d51975]444 StoreTrianglesinFile(mol, TesselStruct, filename, "");
[ef0e6d]445
[357fba]446 // free reference lists
447 if (BoundaryFreeFlag)
448 delete[] (BoundaryPoints);
[3d919e]449};
[6ac7ee]450
[d4fa23]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 */
[e138de]458bool RemoveAllBoundaryPoints(class Tesselation *&TesselStruct, const molecule * const mol, const char * const filename)
[d4fa23]459{
[ce7bfd]460 //Info FunctionInfo(__func__);
[d4fa23]461 int i=0;
462 char number[MAXSTRINGSIZE];
463
464 if ((TesselStruct == NULL) || (TesselStruct->PointsOnBoundary.empty())) {
[47d041]465 ELOG(1, "TesselStruct is empty.");
[d4fa23]466 return false;
467 }
468
469 PointMap::iterator PointRunner;
470 while (!TesselStruct->PointsOnBoundary.empty()) {
[47d041]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 }
[d4fa23]478
479 PointRunner = TesselStruct->PointsOnBoundary.begin();
480 // remove point
[e138de]481 TesselStruct->RemovePointFromTesselatedSurface(PointRunner->second);
[d4fa23]482
483 // store envelope
484 sprintf(number, "-%04d", i++);
[e138de]485 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, number);
[d4fa23]486 }
487
488 return true;
489};
490
[08ef35]491/** Creates a convex envelope from a given non-convex one.
[093645]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
[08ef35]506 * Note: This routine - for free - calculates the difference in volume between convex and
[ee0032]507 * non-convex envelope, as the former is easy to calculate - Tesselation::getVolumeOfConvexEnvelope() - it
[08ef35]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!
[093645]511 * \param *mol molecule
512 * \param *filename name of file
[08ef35]513 * \return volume difference between the non- and the created convex envelope
514 */
[e138de]515double ConvexizeNonconvexEnvelope(class Tesselation *&TesselStruct, const molecule * const mol, const char * const filename)
[08ef35]516{
[ce7bfd]517 //Info FunctionInfo(__func__);
[08ef35]518 double volume = 0;
519 class BoundaryPointSet *point = NULL;
520 class BoundaryLineSet *line = NULL;
[ad37ab]521 bool Concavity = false;
[57066a]522 char dummy[MAXSTRINGSIZE];
[ad37ab]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;
[093645]530
531 // check whether there is something to work on
[08ef35]532 if (TesselStruct == NULL) {
[47d041]533 ELOG(1, "TesselStruct is empty!");
[08ef35]534 return volume;
535 }
536
[b8d215]537 LOG(1, "INFO: Making tesselated surface with " << TesselStruct->TrianglesOnBoundaryCount
538 << " convex ...");
539
[093645]540 // First step: RemovePointFromTesselatedSurface
[1d9b7aa]541 do {
542 Concavity = false;
[57066a]543 sprintf(dummy, "-first-%d", run);
[e138de]544 //CalculateConcavityPerBoundaryPoint(TesselStruct);
545 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
[57066a]546
[1d9b7aa]547 PointRunner = TesselStruct->PointsOnBoundary.begin();
548 PointAdvance = PointRunner; // we need an advanced point, as the PointRunner might get removed
549 while (PointRunner != TesselStruct->PointsOnBoundary.end()) {
550 PointAdvance++;
551 point = PointRunner->second;
[b8d215]552 LOG(2, "INFO: Current point is " << *point << ".");
[1d9b7aa]553 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++) {
554 line = LineRunner->second;
[b8d215]555 LOG(3, "INFO: Current line of point " << *point << " is " << *line << ".");
[e138de]556 if (!line->CheckConvexityCriterion()) {
[57066a]557 // remove the point if needed
[47d041]558 LOG(1, "... point " << *point << " cannot be on convex envelope.");
[e138de]559 volume += TesselStruct->RemovePointFromTesselatedSurface(point);
[57066a]560 sprintf(dummy, "-first-%d", ++run);
[e138de]561 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
[57066a]562 Concavity = true;
563 break;
564 }
[1d9b7aa]565 }
566 PointRunner = PointAdvance;
[093645]567 }
568
[57066a]569 sprintf(dummy, "-second-%d", run);
[e138de]570 //CalculateConcavityPerBoundaryPoint(TesselStruct);
571 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
[093645]572
[1d9b7aa]573 // second step: PickFarthestofTwoBaselines
574 LineRunner = TesselStruct->LinesOnBoundary.begin();
575 LineAdvance = LineRunner; // we need an advanced line, as the LineRunner might get removed
576 while (LineRunner != TesselStruct->LinesOnBoundary.end()) {
577 LineAdvance++;
578 line = LineRunner->second;
[47d041]579 LOG(1, "INFO: Picking farthest baseline for line is " << *line << ".");
[1d9b7aa]580 // take highest of both lines
[e138de]581 if (TesselStruct->IsConvexRectangle(line) == NULL) {
582 const double tmp = TesselStruct->PickFarthestofTwoBaselines(line);
[57066a]583 volume += tmp;
[ad37ab]584 if (tmp != 0.) {
[e138de]585 TesselStruct->FlipBaseline(line);
[57066a]586 Concavity = true;
587 }
[1d9b7aa]588 }
589 LineRunner = LineAdvance;
590 }
[57066a]591 run++;
[1d9b7aa]592 } while (Concavity);
[e138de]593 //CalculateConcavityPerBoundaryPoint(TesselStruct);
594 //StoreTrianglesinFile(mol, filename, "-third");
[093645]595
596 // third step: IsConvexRectangle
[7dea7c]597// LineRunner = TesselStruct->LinesOnBoundary.begin();
598// LineAdvance = LineRunner; // we need an advanced line, as the LineRunner might get removed
599// while (LineRunner != TesselStruct->LinesOnBoundary.end()) {
600// LineAdvance++;
601// line = LineRunner->second;
[47d041]602// LOG(1, "INFO: Current line is " << *line << ".");
[7dea7c]603// //if (LineAdvance != TesselStruct->LinesOnBoundary.end())
[47d041]604// //LOG(1, "INFO: Next line will be " << *(LineAdvance->second) << ".");
[7dea7c]605// if (!line->CheckConvexityCriterion(out)) {
[47d041]606// LOG(1, "INFO: ... line " << *line << " is concave, flipping it.");
[7dea7c]607//
608// // take highest of both lines
[e138de]609// point = TesselStruct->IsConvexRectangle(line);
[7dea7c]610// if (point != NULL)
[e138de]611// volume += TesselStruct->RemovePointFromTesselatedSurface(point);
[7dea7c]612// }
613// LineRunner = LineAdvance;
614// }
[093645]615
[e138de]616 CalculateConcavityPerBoundaryPoint(TesselStruct);
617 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, "");
[0077b5]618
619 // end
[47d041]620 LOG(0, "Volume is " << volume << ".");
[0077b5]621 return volume;
622};
623
[6ac7ee]624
[7dea7c]625/** Stores triangles to file.
626 * \param *out output stream for debugging
627 * \param *mol molecule with atoms and bonds
[71b20e]628 * \param *TesselStruct Tesselation with boundary triangles
[7dea7c]629 * \param *filename prefix of filename
630 * \param *extraSuffix intermediate suffix
631 */
[71b20e]632void StoreTrianglesinFile(const molecule * const mol, const Tesselation * const TesselStruct, const char *filename, const char *extraSuffix)
[7dea7c]633{
[ce7bfd]634 //Info FunctionInfo(__func__);
[caa06ef]635 PointCloudAdaptor< molecule > cloud(const_cast<molecule *>(mol), mol->name);
[7dea7c]636 // 4. Store triangles in tecplot file
637 if (filename != NULL) {
638 if (DoTecplotOutput) {
639 string OutputName(filename);
640 OutputName.append(extraSuffix);
641 OutputName.append(TecplotSuffix);
642 ofstream *tecplot = new ofstream(OutputName.c_str());
[34c43a]643 WriteTecplotFile(tecplot, TesselStruct, cloud, -1);
[7dea7c]644 tecplot->close();
645 delete(tecplot);
646 }
647 if (DoRaster3DOutput) {
648 string OutputName(filename);
649 OutputName.append(extraSuffix);
650 OutputName.append(Raster3DSuffix);
651 ofstream *rasterplot = new ofstream(OutputName.c_str());
[34c43a]652 WriteRaster3dFile(rasterplot, TesselStruct, cloud);
[7dea7c]653 rasterplot->close();
654 delete(rasterplot);
655 }
656 }
657};
[03648b]658
[6ac7ee]659/** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
660 * \param *out output stream for debugging
661 * \param *mol molecule structure with Atom's and Bond's
[776b64]662 * \param *&TesselStruct Tesselation filled with points, lines and triangles on boundary on return
[6bd7e0]663 * \param *&LCList atoms in LinkedCell_deprecated list
[57066a]664 * \param RADIUS radius of the virtual sphere
[6ac7ee]665 * \param *filename filename prefix for output of vertex data
[4fc93f]666 * \return true - tesselation successful, false - tesselation failed
[6ac7ee]667 */
[6bd7e0]668bool FindNonConvexBorder(molecule* const mol, Tesselation *&TesselStruct, const LinkedCell_deprecated *&LCList, const double RADIUS, const char *filename = NULL)
[03648b]669{
[ce7bfd]670 //Info FunctionInfo(__func__);
[3d919e]671 bool freeLC = false;
[4fc93f]672 bool status = false;
[6613ec]673 CandidateForTesselation *baseline = NULL;
[1e168b]674 bool OneLoopWithoutSuccessFlag = true; // marks whether we went once through all baselines without finding any without two triangles
[a2a2f7]675// bool TesselationFailFlag = false;
[357fba]676
[a7b761b]677 mol->getAtomCount();
[357fba]678
[776b64]679 if (TesselStruct == NULL) {
[47d041]680 LOG(1, "Allocating Tesselation struct ...");
[776b64]681 TesselStruct= new Tesselation;
[ef0e6d]682 } else {
[776b64]683 delete(TesselStruct);
[47d041]684 LOG(1, "Re-Allocating Tesselation struct ...");
[776b64]685 TesselStruct = new Tesselation;
[3d919e]686 }
[ad37ab]687
[57066a]688 // initialise Linked Cell
[caa06ef]689 PointCloudAdaptor< molecule > cloud(mol, mol->name);
[3d919e]690 if (LCList == NULL) {
[6bd7e0]691 LCList = new LinkedCell_deprecated(cloud, 2.*RADIUS);
[3d919e]692 freeLC = true;
693 }
694
[57066a]695 // 1. get starting triangle
[ce70970]696 if (!TesselStruct->FindStartingTriangle(RADIUS, LCList)) {
[47d041]697 ELOG(0, "No valid starting triangle found.");
[b5c2d7]698 //performCriticalExit();
[ce70970]699 }
[f8bd7d]700 if (filename != NULL) {
701 if ((DoSingleStepOutput && ((TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
[34c43a]702 TesselStruct->Output(filename, cloud);
[f8bd7d]703 }
704 }
[3d919e]705
[57066a]706 // 2. expand from there
[1e168b]707 while ((!TesselStruct->OpenLines.empty()) && (OneLoopWithoutSuccessFlag)) {
[b40a93]708 (cerr << "There are " << TesselStruct->TrianglesOnBoundary.size() << " triangles and " << TesselStruct->OpenLines.size() << " open lines to scan for candidates." << endl);
709 // 2a. print OpenLines without candidates
[47d041]710 LOG(1, "There are the following open lines to scan for a candidates:");
[1e168b]711 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
[b40a93]712 if (Runner->second->pointlist.empty())
[47d041]713 LOG(1, " " << *(Runner->second));
[1e168b]714
[734816]715 // 2b. find best candidate for each OpenLine
[a2a2f7]716 const bool TesselationFailFlag = TesselStruct->FindCandidatesforOpenLines(RADIUS, LCList);
717 ASSERT( TesselationFailFlag,
718 "FindNonConvexBorder() - at least one open line without candidate exists.");
[3d919e]719
[734816]720 // 2c. print OpenLines with candidates again
[47d041]721 LOG(1, "There are " << TesselStruct->OpenLines.size() << " open lines to scan for the best candidates:");
[1e168b]722 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
[47d041]723 LOG(1, " " << *(Runner->second));
[1e168b]724
[734816]725 // 2d. search for smallest ShortestAngle among all candidates
726 double ShortestAngle = 4.*M_PI;
[1e168b]727 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++) {
728 if (Runner->second->ShortestAngle < ShortestAngle) {
729 baseline = Runner->second;
730 ShortestAngle = baseline->ShortestAngle;
[47d041]731 LOG(1, "New best candidate is " << *baseline->BaseLine << " with point " << *(*baseline->pointlist.begin()) << " and angle " << baseline->ShortestAngle);
[1e168b]732 }
733 }
[734816]734 // 2e. if we found one, add candidate
[f67b6e]735 if ((ShortestAngle == 4.*M_PI) || (baseline->pointlist.empty()))
[7dea7c]736 OneLoopWithoutSuccessFlag = false;
[1e168b]737 else {
[474961]738 TesselStruct->AddCandidatePolygon(*baseline, RADIUS, LCList);
[1e168b]739 }
740
[734816]741 // 2f. write temporary envelope
[1e168b]742 if (filename != NULL) {
743 if ((DoSingleStepOutput && ((TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
[34c43a]744 TesselStruct->Output(filename, cloud);
[1e168b]745 }
[3d919e]746 }
747 }
[4fc93f]748// // check envelope for consistency
749// status = CheckListOfBaselines(TesselStruct);
750//
751// // look whether all points are inside of the convex envelope, otherwise add them via degenerated triangles
752// //->InsertStraddlingPoints(mol, LCList);
[9879f6]753// for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
[57066a]754// class TesselPoint *Runner = NULL;
[9879f6]755// Runner = *iter;
[47d041]756// LOG(1, "Checking on " << Runner->Name << " ... ");
[e138de]757// if (!->IsInnerPoint(Runner, LCList)) {
[47d041]758// LOG(2, Runner->Name << " is outside of envelope, adding via degenerated triangles.");
[e138de]759// ->AddBoundaryPointByDegeneratedTriangle(Runner, LCList);
[57066a]760// } else {
[47d041]761// LOG(2, Runner->Name << " is inside of or on envelope.");
[57066a]762// }
763// }
[357fba]764
[f67b6e]765// // Purges surplus triangles.
766// TesselStruct->RemoveDegeneratedTriangles();
[b32dbb]767//
768// // check envelope for consistency
769// status = CheckListOfBaselines(TesselStruct);
[b998c3]770
[b8d215]771// cout << "before correction" << endl;
[c72112]772
[b998c3]773 // store before correction
[c72112]774 StoreTrianglesinFile(mol, TesselStruct, filename, "");
[b998c3]775
[6613ec]776// // correct degenerated polygons
777// TesselStruct->CorrectAllDegeneratedPolygons();
778//
[e69c87]779 // check envelope for consistency
780 status = CheckListOfBaselines(TesselStruct);
[ef0e6d]781
[57066a]782 // write final envelope
[e138de]783 CalculateConcavityPerBoundaryPoint(TesselStruct);
[b8d215]784// cout << "after correction" << endl;
[c72112]785 StoreTrianglesinFile(mol, TesselStruct, filename, "");
[8c54a3]786
[3d919e]787 if (freeLC)
788 delete(LCList);
[4fc93f]789
790 return status;
[6ac7ee]791};
[03648b]792
[57066a]793
[ad37ab]794/** Finds a hole of sufficient size in \a *mols to embed \a *srcmol into it.
[ca2587]795 * \param *out output stream for debugging
[ad37ab]796 * \param *mols molecules in the domain to embed in between
797 * \param *srcmol embedding molecule
[ca2587]798 * \return *Vector new center of \a *srcmol for embedding relative to \a this
799 */
[e138de]800Vector* FindEmbeddingHole(MoleculeListClass *mols, molecule *srcmol)
[ca2587]801{
[ce7bfd]802 //Info FunctionInfo(__func__);
[ca2587]803 Vector *Center = new Vector;
804 Center->Zero();
805 // calculate volume/shape of \a *srcmol
806
807 // find embedding holes
808
809 // if more than one, let user choose
810
811 // return embedding center
812 return Center;
813};
814
Note: See TracBrowser for help on using the repository browser.