source: src/boundary.cpp@ d557374

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 d557374 was 9d83b6, checked in by Frederik Heber <heber@…>, 14 years ago

BondedParticleInfo now has vector<BondList>

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