source: src/boundary.cpp@ 5605793

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

molecule::erase() is only used by atom::removeFromMolecule().

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