source: src/boundary.cpp@ b25fa3

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

FIX: FillVoidWithMolecule() now centers filler molecule at its center of gravity.

  • this is the only sensible option if we later rotate the molecule.
  • atom::clone() reduced a lot, as copy constructors contains it all.
  • FillVoidWithMolecule() - filler is now selected to reside entirely within the domain. Otherwise, we seg'fault on save on exit, as one of the father atoms for all copied atoms is missing and hence, we cannot look at its additional...Data for various parsers.
  • new function molecule::removeAtomsInMolecule() which destroys all the molecule's atoms.

TESTFIXES:

  • Filling/3: filled water box has changed due to different center of water molecules.
  • Property mode set to 100644
File size: 61.3 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
[6e5084]20#include "Actions/MoleculeAction/RotateToPrincipalAxisSystemAction.hpp"
[d74077]21#include "BoundaryPointSet.hpp"
22#include "BoundaryLineSet.hpp"
23#include "BoundaryTriangleSet.hpp"
24#include "CandidateForTesselation.hpp"
[8f4df1]25//#include "TesselPoint.hpp"
[cbc5fb]26#include "World.hpp"
[f66195]27#include "atom.hpp"
28#include "bond.hpp"
[8eb17a]29#include "boundary.hpp"
[f66195]30#include "config.hpp"
31#include "element.hpp"
[952f38]32#include "Helpers/helpers.hpp"
[ad011c]33#include "CodePatterns/Info.hpp"
[f66195]34#include "linkedcell.hpp"
[ad011c]35#include "CodePatterns/Verbose.hpp"
36#include "CodePatterns/Log.hpp"
[f66195]37#include "molecule.hpp"
38#include "tesselation.hpp"
39#include "tesselationhelpers.hpp"
[b34306]40#include "World.hpp"
[57f243]41#include "LinearAlgebra/Plane.hpp"
[cca9ef]42#include "LinearAlgebra/RealSpaceMatrix.hpp"
[84c494]43#include "Box.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;
176 Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, nr)
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)
[e138de]379 TesselStruct->TesselateOnBoundary(mol);
[3d919e]380
[357fba]381 // 3c. check whether all atoms lay inside the boundary, if not, add to boundary points, segment triangle into three with the new point
[e138de]382 if (!TesselStruct->InsertStraddlingPoints(mol, LCList))
[58ed4a]383 DoeLog(1) && (eLog()<< Verbose(1) << "Insertion of straddling points failed!" << endl);
[3d919e]384
[a67d19]385 DoLog(0) && (Log() << Verbose(0) << "I created " << TesselStruct->TrianglesOnBoundary.size() << " intermediate triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points." << endl);
[ef0e6d]386
387 // 4. Store triangles in tecplot file
[d51975]388 StoreTrianglesinFile(mol, TesselStruct, filename, "_intermed");
[ef0e6d]389
[357fba]390 // 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]391 bool AllConvex = true;
[093645]392 class BoundaryLineSet *line = NULL;
393 do {
394 AllConvex = true;
[776b64]395 for (LineMap::iterator LineRunner = TesselStruct->LinesOnBoundary.begin(); LineRunner != TesselStruct->LinesOnBoundary.end(); LineRunner++) {
[093645]396 line = LineRunner->second;
[a67d19]397 DoLog(1) && (Log() << Verbose(1) << "INFO: Current line is " << *line << "." << endl);
[e138de]398 if (!line->CheckConvexityCriterion()) {
[a67d19]399 DoLog(1) && (Log() << Verbose(1) << "... line " << *line << " is concave, flipping it." << endl);
[093645]400
401 // flip the line
[e138de]402 if (TesselStruct->PickFarthestofTwoBaselines(line) == 0.)
[58ed4a]403 DoeLog(1) && (eLog()<< Verbose(1) << "Correction of concave baselines failed!" << endl);
[57066a]404 else {
[e138de]405 TesselStruct->FlipBaseline(line);
[a67d19]406 DoLog(1) && (Log() << Verbose(1) << "INFO: Correction of concave baselines worked." << endl);
[accebe]407 LineRunner = TesselStruct->LinesOnBoundary.begin(); // LineRunner may have been erase if line was deleted from LinesOnBoundary
[57066a]408 }
[093645]409 }
410 }
411 } while (!AllConvex);
[3d919e]412
[ef0e6d]413 // 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]414// if (!TesselStruct->CorrectConcaveTesselPoints(out))
[e138de]415// Log() << Verbose(1) << "Correction of concave tesselpoints failed!" << endl;
[ef0e6d]416
[a67d19]417 DoLog(0) && (Log() << Verbose(0) << "I created " << TesselStruct->TrianglesOnBoundary.size() << " triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points." << endl);
[3d919e]418
[357fba]419 // 4. Store triangles in tecplot file
[d51975]420 StoreTrianglesinFile(mol, TesselStruct, filename, "");
[ef0e6d]421
[357fba]422 // free reference lists
423 if (BoundaryFreeFlag)
424 delete[] (BoundaryPoints);
[3d919e]425};
[6ac7ee]426
[d4fa23]427/** For testing removes one boundary point after another to check for leaks.
428 * \param *out output stream for debugging
429 * \param *TesselStruct Tesselation containing envelope with boundary points
430 * \param *mol molecule
431 * \param *filename name of file
432 * \return true - all removed, false - something went wrong
433 */
[e138de]434bool RemoveAllBoundaryPoints(class Tesselation *&TesselStruct, const molecule * const mol, const char * const filename)
[d4fa23]435{
[f67b6e]436 Info FunctionInfo(__func__);
[d4fa23]437 int i=0;
438 char number[MAXSTRINGSIZE];
439
440 if ((TesselStruct == NULL) || (TesselStruct->PointsOnBoundary.empty())) {
[58ed4a]441 DoeLog(1) && (eLog()<< Verbose(1) << "TesselStruct is empty." << endl);
[d4fa23]442 return false;
443 }
444
445 PointMap::iterator PointRunner;
446 while (!TesselStruct->PointsOnBoundary.empty()) {
[a67d19]447 DoLog(1) && (Log() << Verbose(1) << "Remaining points are: ");
[d4fa23]448 for (PointMap::iterator PointSprinter = TesselStruct->PointsOnBoundary.begin(); PointSprinter != TesselStruct->PointsOnBoundary.end(); PointSprinter++)
[a67d19]449 DoLog(0) && (Log() << Verbose(0) << *(PointSprinter->second) << "\t");
450 DoLog(0) && (Log() << Verbose(0) << endl);
[d4fa23]451
452 PointRunner = TesselStruct->PointsOnBoundary.begin();
453 // remove point
[e138de]454 TesselStruct->RemovePointFromTesselatedSurface(PointRunner->second);
[d4fa23]455
456 // store envelope
457 sprintf(number, "-%04d", i++);
[e138de]458 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, number);
[d4fa23]459 }
460
461 return true;
462};
463
[08ef35]464/** Creates a convex envelope from a given non-convex one.
[093645]465 * -# First step, remove concave spots, i.e. singular "dents"
466 * -# We go through all PointsOnBoundary.
467 * -# We CheckConvexityCriterion() for all its lines.
468 * -# If all its lines are concave, it cannot be on the convex envelope.
469 * -# Hence, we remove it and re-create all its triangles from its getCircleOfConnectedPoints()
470 * -# We calculate the additional volume.
471 * -# We go over all lines until none yields a concavity anymore.
472 * -# Second step, remove concave lines, i.e. line-shape "dents"
473 * -# We go through all LinesOnBoundary
474 * -# We CheckConvexityCriterion()
475 * -# If it returns concave, we flip the line in this quadrupel of points (abusing the degeneracy of the tesselation)
476 * -# We CheckConvexityCriterion(),
477 * -# if it's concave, we continue
478 * -# if not, we mark an error and stop
[08ef35]479 * Note: This routine - for free - calculates the difference in volume between convex and
480 * non-convex envelope, as the former is easy to calculate - VolumeOfConvexEnvelope() - it
481 * can be used to compute volumes of arbitrary shapes.
482 * \param *out output stream for debugging
483 * \param *TesselStruct non-convex envelope, is changed in return!
[093645]484 * \param *mol molecule
485 * \param *filename name of file
[08ef35]486 * \return volume difference between the non- and the created convex envelope
487 */
[e138de]488double ConvexizeNonconvexEnvelope(class Tesselation *&TesselStruct, const molecule * const mol, const char * const filename)
[08ef35]489{
[f67b6e]490 Info FunctionInfo(__func__);
[08ef35]491 double volume = 0;
492 class BoundaryPointSet *point = NULL;
493 class BoundaryLineSet *line = NULL;
[ad37ab]494 bool Concavity = false;
[57066a]495 char dummy[MAXSTRINGSIZE];
[ad37ab]496 PointMap::iterator PointRunner;
497 PointMap::iterator PointAdvance;
498 LineMap::iterator LineRunner;
499 LineMap::iterator LineAdvance;
500 TriangleMap::iterator TriangleRunner;
501 TriangleMap::iterator TriangleAdvance;
502 int run = 0;
[093645]503
504 // check whether there is something to work on
[08ef35]505 if (TesselStruct == NULL) {
[58ed4a]506 DoeLog(1) && (eLog()<< Verbose(1) << "TesselStruct is empty!" << endl);
[08ef35]507 return volume;
508 }
509
[093645]510 // First step: RemovePointFromTesselatedSurface
[1d9b7aa]511 do {
512 Concavity = false;
[57066a]513 sprintf(dummy, "-first-%d", run);
[e138de]514 //CalculateConcavityPerBoundaryPoint(TesselStruct);
515 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
[57066a]516
[1d9b7aa]517 PointRunner = TesselStruct->PointsOnBoundary.begin();
518 PointAdvance = PointRunner; // we need an advanced point, as the PointRunner might get removed
519 while (PointRunner != TesselStruct->PointsOnBoundary.end()) {
520 PointAdvance++;
521 point = PointRunner->second;
[a67d19]522 DoLog(1) && (Log() << Verbose(1) << "INFO: Current point is " << *point << "." << endl);
[1d9b7aa]523 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++) {
524 line = LineRunner->second;
[a67d19]525 DoLog(1) && (Log() << Verbose(1) << "INFO: Current line of point " << *point << " is " << *line << "." << endl);
[e138de]526 if (!line->CheckConvexityCriterion()) {
[57066a]527 // remove the point if needed
[a67d19]528 DoLog(1) && (Log() << Verbose(1) << "... point " << *point << " cannot be on convex envelope." << endl);
[e138de]529 volume += TesselStruct->RemovePointFromTesselatedSurface(point);
[57066a]530 sprintf(dummy, "-first-%d", ++run);
[e138de]531 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
[57066a]532 Concavity = true;
533 break;
534 }
[1d9b7aa]535 }
536 PointRunner = PointAdvance;
[093645]537 }
538
[57066a]539 sprintf(dummy, "-second-%d", run);
[e138de]540 //CalculateConcavityPerBoundaryPoint(TesselStruct);
541 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
[093645]542
[1d9b7aa]543 // second step: PickFarthestofTwoBaselines
544 LineRunner = TesselStruct->LinesOnBoundary.begin();
545 LineAdvance = LineRunner; // we need an advanced line, as the LineRunner might get removed
546 while (LineRunner != TesselStruct->LinesOnBoundary.end()) {
547 LineAdvance++;
548 line = LineRunner->second;
[a67d19]549 DoLog(1) && (Log() << Verbose(1) << "INFO: Picking farthest baseline for line is " << *line << "." << endl);
[1d9b7aa]550 // take highest of both lines
[e138de]551 if (TesselStruct->IsConvexRectangle(line) == NULL) {
552 const double tmp = TesselStruct->PickFarthestofTwoBaselines(line);
[57066a]553 volume += tmp;
[ad37ab]554 if (tmp != 0.) {
[e138de]555 TesselStruct->FlipBaseline(line);
[57066a]556 Concavity = true;
557 }
[1d9b7aa]558 }
559 LineRunner = LineAdvance;
560 }
[57066a]561 run++;
[1d9b7aa]562 } while (Concavity);
[e138de]563 //CalculateConcavityPerBoundaryPoint(TesselStruct);
564 //StoreTrianglesinFile(mol, filename, "-third");
[093645]565
566 // third step: IsConvexRectangle
[7dea7c]567// LineRunner = TesselStruct->LinesOnBoundary.begin();
568// LineAdvance = LineRunner; // we need an advanced line, as the LineRunner might get removed
569// while (LineRunner != TesselStruct->LinesOnBoundary.end()) {
570// LineAdvance++;
571// line = LineRunner->second;
[e138de]572// Log() << Verbose(1) << "INFO: Current line is " << *line << "." << endl;
[7dea7c]573// //if (LineAdvance != TesselStruct->LinesOnBoundary.end())
[e138de]574// //Log() << Verbose(1) << "INFO: Next line will be " << *(LineAdvance->second) << "." << endl;
[7dea7c]575// if (!line->CheckConvexityCriterion(out)) {
[e138de]576// Log() << Verbose(1) << "... line " << *line << " is concave, flipping it." << endl;
[7dea7c]577//
578// // take highest of both lines
[e138de]579// point = TesselStruct->IsConvexRectangle(line);
[7dea7c]580// if (point != NULL)
[e138de]581// volume += TesselStruct->RemovePointFromTesselatedSurface(point);
[7dea7c]582// }
583// LineRunner = LineAdvance;
584// }
[093645]585
[e138de]586 CalculateConcavityPerBoundaryPoint(TesselStruct);
587 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, "");
[0077b5]588
589 // end
[a67d19]590 DoLog(0) && (Log() << Verbose(0) << "Volume is " << volume << "." << endl);
[0077b5]591 return volume;
592};
593
[6ac7ee]594
[357fba]595/** Determines the volume of a cluster.
596 * Determines first the convex envelope, then tesselates it and calculates its volume.
[6ac7ee]597 * \param *out output stream for debugging
[357fba]598 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
599 * \param *configuration needed for path to store convex envelope file
600 * \return determined volume of the cluster in cubed config:GetIsAngstroem()
[3d919e]601 */
[e138de]602double VolumeOfConvexEnvelope(class Tesselation *TesselStruct, class config *configuration)
[357fba]603{
[f67b6e]604 Info FunctionInfo(__func__);
[357fba]605 bool IsAngstroem = configuration->GetIsAngstroem();
606 double volume = 0.;
[ad37ab]607 Vector x;
608 Vector y;
[6ac7ee]609
[357fba]610 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
611 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++)
612 { // go through every triangle, calculate volume of its pyramid with CoG as peak
[8f215d]613 x = runner->second->getEndpoint(0) - runner->second->getEndpoint(1);
614 y = runner->second->getEndpoint(0) - runner->second->getEndpoint(2);
615 const double a = x.Norm();
616 const double b = y.Norm();
617 const double c = runner->second->getEndpoint(2).distance(runner->second->getEndpoint(1));
[ad37ab]618 const double G = sqrt(((a + b + c) * (a + b + c) - 2 * (a * a + b * b + c * c)) / 16.); // area of tesselated triangle
[8f215d]619 x = runner->second->getPlane().getNormal();
620 x.Scale(runner->second->getEndpoint(1).ScalarProduct(x));
[ad37ab]621 const double h = x.Norm(); // distance of CoG to triangle
622 const double PyramidVolume = (1. / 3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
[f67b6e]623 Log() << Verbose(1) << "Area of triangle is " << setprecision(10) << G << " "
[357fba]624 << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is "
625 << h << " and the volume is " << PyramidVolume << " "
626 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
627 volume += PyramidVolume;
[3d919e]628 }
[7f4bee]629 Log() << Verbose(0) << "RESULT: The summed volume is " << setprecision(6)
[357fba]630 << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3."
631 << endl;
[6ac7ee]632
[357fba]633 return volume;
[7dea7c]634};
635
636/** Stores triangles to file.
637 * \param *out output stream for debugging
638 * \param *mol molecule with atoms and bonds
[71b20e]639 * \param *TesselStruct Tesselation with boundary triangles
[7dea7c]640 * \param *filename prefix of filename
641 * \param *extraSuffix intermediate suffix
642 */
[71b20e]643void StoreTrianglesinFile(const molecule * const mol, const Tesselation * const TesselStruct, const char *filename, const char *extraSuffix)
[7dea7c]644{
[f67b6e]645 Info FunctionInfo(__func__);
[7dea7c]646 // 4. Store triangles in tecplot file
647 if (filename != NULL) {
648 if (DoTecplotOutput) {
649 string OutputName(filename);
650 OutputName.append(extraSuffix);
651 OutputName.append(TecplotSuffix);
652 ofstream *tecplot = new ofstream(OutputName.c_str());
[6a7f78c]653 WriteTecplotFile(tecplot, TesselStruct, mol, -1);
[7dea7c]654 tecplot->close();
655 delete(tecplot);
656 }
657 if (DoRaster3DOutput) {
658 string OutputName(filename);
659 OutputName.append(extraSuffix);
660 OutputName.append(Raster3DSuffix);
661 ofstream *rasterplot = new ofstream(OutputName.c_str());
[e138de]662 WriteRaster3dFile(rasterplot, TesselStruct, mol);
[7dea7c]663 rasterplot->close();
664 delete(rasterplot);
665 }
666 }
667};
[03648b]668
[357fba]669/** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
670 * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
[accebe]671 * TODO: Here, we need a VolumeOfGeneralEnvelope (i.e. non-convex one)
[357fba]672 * \param *out output stream for debugging
673 * \param *configuration needed for path to store convex envelope file
674 * \param *mol molecule structure representing the cluster
[776b64]675 * \param *&TesselStruct Tesselation structure with triangles on return
[357fba]676 * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead.
677 * \param celldensity desired average density in final cell
[8c54a3]678 */
[e138de]679void PrepareClustersinWater(config *configuration, molecule *mol, double ClusterVolume, double celldensity)
[357fba]680{
[f67b6e]681 Info FunctionInfo(__func__);
[fa649a]682 bool IsAngstroem = true;
[ad37ab]683 double *GreatestDiameter = NULL;
684 Boundaries *BoundaryPoints = NULL;
685 class Tesselation *TesselStruct = NULL;
686 Vector BoxLengths;
687 int repetition[NDIM] = { 1, 1, 1 };
688 int TotalNoClusters = 1;
689 double totalmass = 0.;
690 double clustervolume = 0.;
691 double cellvolume = 0.;
692
[6e5084]693 // transform to PAS by Action
694 Vector MainAxis(0.,0.,1.);
695 MoleculeRotateToPrincipalAxisSystem(MainAxis);
[3d919e]696
[ad37ab]697 IsAngstroem = configuration->GetIsAngstroem();
[e138de]698 BoundaryPoints = GetBoundaryPoints(mol, TesselStruct);
[bdc91e]699 GreatestDiameter = GetDiametersOfCluster(BoundaryPoints, mol, TesselStruct, IsAngstroem);
[af2c424]700 LinkedCell *LCList = new LinkedCell(*mol, 10.);
[bdc91e]701 FindConvexBorder(mol, BoundaryPoints, TesselStruct, (const LinkedCell *&)LCList, NULL);
[accebe]702 delete (LCList);
[bdc91e]703 delete[] BoundaryPoints;
[accebe]704
[ad37ab]705
706 // some preparations beforehand
[357fba]707 if (ClusterVolume == 0)
[e138de]708 clustervolume = VolumeOfConvexEnvelope(TesselStruct, configuration);
[357fba]709 else
710 clustervolume = ClusterVolume;
[ad37ab]711
[bdc91e]712 delete TesselStruct;
713
[357fba]714 for (int i = 0; i < NDIM; i++)
715 TotalNoClusters *= repetition[i];
[8c54a3]716
[357fba]717 // sum up the atomic masses
[9879f6]718 for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
[83f176]719 totalmass += (*iter)->getType()->getMass();
[ad37ab]720 }
[a67d19]721 DoLog(0) && (Log() << Verbose(0) << "RESULT: The summed mass is " << setprecision(10) << totalmass << " atomicmassunit." << endl);
722 DoLog(0) && (Log() << Verbose(0) << "RESULT: The average density is " << setprecision(10) << totalmass / clustervolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl);
[8c54a3]723
[357fba]724 // solve cubic polynomial
[a67d19]725 DoLog(1) && (Log() << Verbose(1) << "Solving equidistant suspension in water problem ..." << endl);
[357fba]726 if (IsAngstroem)
[ad37ab]727 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_A - (totalmass / clustervolume)) / (celldensity - 1);
[357fba]728 else
[ad37ab]729 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_a0 - (totalmass / clustervolume)) / (celldensity - 1);
[a67d19]730 DoLog(1) && (Log() << Verbose(1) << "Cellvolume needed for a density of " << celldensity << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl);
[ad37ab]731
732 double minimumvolume = TotalNoClusters * (GreatestDiameter[0] * GreatestDiameter[1] * GreatestDiameter[2]);
[a67d19]733 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]734 if (minimumvolume > cellvolume) {
[58ed4a]735 DoeLog(1) && (eLog()<< Verbose(1) << "the containing box already has a greater volume than the envisaged cell volume!" << endl);
[a67d19]736 DoLog(0) && (Log() << Verbose(0) << "Setting Box dimensions to minimum possible, the greatest diameters." << endl);
[ad37ab]737 for (int i = 0; i < NDIM; i++)
[0a4f7f]738 BoxLengths[i] = GreatestDiameter[i];
[e138de]739 mol->CenterEdge(&BoxLengths);
[ad37ab]740 } else {
[0a4f7f]741 BoxLengths[0] = (repetition[0] * GreatestDiameter[0] + repetition[1] * GreatestDiameter[1] + repetition[2] * GreatestDiameter[2]);
742 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]);
743 BoxLengths[2] = minimumvolume - cellvolume;
[ad37ab]744 double x0 = 0.;
745 double x1 = 0.;
746 double x2 = 0.;
[0a4f7f]747 if (gsl_poly_solve_cubic(BoxLengths[0], BoxLengths[1], BoxLengths[2], &x0, &x1, &x2) == 1) // either 1 or 3 on return
[a67d19]748 DoLog(0) && (Log() << Verbose(0) << "RESULT: The resulting spacing is: " << x0 << " ." << endl);
[ad37ab]749 else {
[a67d19]750 DoLog(0) && (Log() << Verbose(0) << "RESULT: The resulting spacings are: " << x0 << " and " << x1 << " and " << x2 << " ." << endl);
[ad37ab]751 x0 = x2; // sorted in ascending order
[357fba]752 }
[8c54a3]753
[ad37ab]754 cellvolume = 1.;
755 for (int i = 0; i < NDIM; i++) {
[0a4f7f]756 BoxLengths[i] = repetition[i] * (x0 + GreatestDiameter[i]);
757 cellvolume *= BoxLengths[i];
[8c54a3]758 }
[ad37ab]759
760 // set new box dimensions
[a67d19]761 DoLog(0) && (Log() << Verbose(0) << "Translating to box with these boundaries." << endl);
[ad37ab]762 mol->SetBoxDimension(&BoxLengths);
[e138de]763 mol->CenterInBox();
[ad37ab]764 }
[bdc91e]765 delete GreatestDiameter;
[357fba]766 // update Box of atoms by boundary
767 mol->SetBoxDimension(&BoxLengths);
[8cbb97]768 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]769};
[8c54a3]770
771
[eee966]772/** Fills the empty space around other molecules' surface of the simulation box with a filler.
[357fba]773 * \param *out output stream for debugging
774 * \param *List list of molecules already present in box
775 * \param *TesselStruct contains tesselated surface
776 * \param *filler molecule which the box is to be filled with
777 * \param configuration contains box dimensions
[775d133]778 * \param MaxDistance fills in molecules only up to this distance (set to -1 if whole of the domain)
[357fba]779 * \param distance[NDIM] distance between filling molecules in each direction
[9473f6]780 * \param boundary length of boundary zone between molecule and filling mollecules
[71b20e]781 * \param epsilon distance to surface which is not filled
[357fba]782 * \param RandAtomDisplacement maximum distance for random displacement per atom
783 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
784 * \param DoRandomRotation true - do random rotiations, false - don't
785 * \return *mol pointer to new molecule with filled atoms
[6ac7ee]786 */
[775d133]787molecule * 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);
[e08c46]820 for(molecule::iterator AtomRunner = filler->begin(); AtomRunner != filler->end(); ++AtomRunner)
821 for(BondList::iterator BondRunner = (*AtomRunner)->ListOfBonds.begin(); BondRunner != (*AtomRunner)->ListOfBonds.end(); ++BondRunner)
822 if ((*BondRunner)->leftatom == *AtomRunner)
[e0aee2b]823 DoLog(2) && (Log() << Verbose(2) << " " << *(*BondRunner) << endl);
[8c54a3]824
[e0aee2b]825 atom * CopyAtoms[FillerCount];
[ef0e6d]826
[357fba]827 // calculate filler grid in [0,1]^3
[5108e1]828 FillerDistance = MInverse * Vector(distance[0], distance[1], distance[2]);
[71b20e]829 for(int i=0;i<NDIM;i++)
[8cbb97]830 N[i] = (int) ceil(1./FillerDistance[i]);
[a67d19]831 DoLog(1) && (Log() << Verbose(1) << "INFO: Grid steps are " << N[0] << ", " << N[1] << ", " << N[2] << "." << endl);
[8c54a3]832
[d6eb80]833 // initialize seed of random number generator to current time
834 srand ( time(NULL) );
835
[357fba]836 // go over [0,1]^3 filler grid
837 for (n[0] = 0; n[0] < N[0]; n[0]++)
838 for (n[1] = 0; n[1] < N[1]; n[1]++)
839 for (n[2] = 0; n[2] < N[2]; n[2]++) {
840 // calculate position of current grid vector in untransformed box
[5108e1]841 CurrentPosition = M * Vector((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
[30d9e7]842 // create molecule random translation vector ...
843 for (int i=0;i<NDIM;i++)
[8cbb97]844 FillerTranslations[i] = RandomMolDisplacement*(rand()/(RAND_MAX/2.) - 1.);
[a67d19]845 DoLog(2) && (Log() << Verbose(2) << "INFO: Current Position is " << CurrentPosition << "+" << FillerTranslations << "." << endl);
[8c54a3]846
[30d9e7]847 // go through all atoms
[e0aee2b]848 for (int i=0;i<FillerCount;i++)
[c5805a]849 CopyAtoms[i] = NULL;
[0b15bb]850
851 // have same rotation angles for all molecule's atoms
852 if (DoRandomRotation)
853 for (int i=0;i<NDIM;i++)
[9df680]854 phi[i] = (rand()/RAND_MAX)*(2.*M_PI);
[0b15bb]855
[e0aee2b]856 for(molecule::const_iterator iter = filler->begin(); iter !=filler->end();++iter){
[8c54a3]857
[30d9e7]858 // create atomic random translation vector ...
[357fba]859 for (int i=0;i<NDIM;i++)
[8cbb97]860 AtomTranslations[i] = RandomAtomDisplacement*(rand()/(RAND_MAX/2.) - 1.);
[8c54a3]861
[30d9e7]862 // ... and rotation matrix
863 if (DoRandomRotation) {
[a679d1]864 Rotations.set(0,0, cos(phi[0]) *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2])));
865 Rotations.set(0,1, sin(phi[0]) *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2])));
866 Rotations.set(0,2, cos(phi[1])*sin(phi[2]) );
867 Rotations.set(1,0, -sin(phi[0])*cos(phi[1]) );
868 Rotations.set(1,1, cos(phi[0])*cos(phi[1]) );
869 Rotations.set(1,2, sin(phi[1]) );
870 Rotations.set(2,0, -cos(phi[0]) *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2])));
871 Rotations.set(2,1, -sin(phi[0]) *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2])));
872 Rotations.set(2,2, cos(phi[1])*cos(phi[2]) );
[30d9e7]873 }
[8c54a3]874
[30d9e7]875 // ... and put at new position
[d74077]876 Inserter = (*iter)->getPosition();
[30d9e7]877 if (DoRandomRotation)
[5108e1]878 Inserter *= Rotations;
[8cbb97]879 Inserter += AtomTranslations + FillerTranslations + CurrentPosition;
[30d9e7]880
881 // check whether inserter is inside box
[5108e1]882 Inserter *= MInverse;
[30d9e7]883 FillIt = true;
[357fba]884 for (int i=0;i<NDIM;i++)
[8cbb97]885 FillIt = FillIt && (Inserter[i] >= -MYEPSILON) && ((Inserter[i]-1.) <= MYEPSILON);
[5108e1]886 Inserter *= M;
[30d9e7]887
888 // Check whether point is in- or outside
889 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
890 // get linked cell list
[c5805a]891 if (TesselStruct[(*ListRunner)] != NULL) {
[8db598]892 const double distance = (TesselStruct[(*ListRunner)]->GetDistanceToSurface(Inserter, LCList[(*ListRunner)]));
893 FillIt = FillIt && (distance > boundary) && ((MaxDistance < 0) || (MaxDistance > distance));
[30d9e7]894 }
895 }
896 // insert into Filling
897 if (FillIt) {
[a67d19]898 DoLog(1) && (Log() << Verbose(1) << "INFO: Position at " << Inserter << " is outer point." << endl);
[357fba]899 // copy atom ...
[a7b761b]900 CopyAtoms[(*iter)->nr] = (*iter)->clone();
[d74077]901 (*CopyAtoms[(*iter)->nr]).setPosition(Inserter);
[9879f6]902 Filling->AddAtom(CopyAtoms[(*iter)->nr]);
[d74077]903 DoLog(1) && (Log() << Verbose(1) << "Filling atom " << **iter << ", translated to " << AtomTranslations << ", at final position is " << (CopyAtoms[(*iter)->nr]->getPosition()) << "." << endl);
[30d9e7]904 } else {
[a67d19]905 DoLog(1) && (Log() << Verbose(1) << "INFO: Position at " << Inserter << " is inner point, within boundary or outside of MaxDistance." << endl);
[a7b761b]906 CopyAtoms[(*iter)->nr] = NULL;
[c5805a]907 continue;
[357fba]908 }
[a837d0]909 }
910 // go through all bonds and add as well
[e08c46]911 for(molecule::iterator AtomRunner = filler->begin(); AtomRunner != filler->end(); ++AtomRunner)
912 for(BondList::iterator BondRunner = (*AtomRunner)->ListOfBonds.begin(); BondRunner != (*AtomRunner)->ListOfBonds.end(); ++BondRunner)
913 if ((*BondRunner)->leftatom == *AtomRunner) {
914 Binder = (*BondRunner);
915 if ((CopyAtoms[Binder->leftatom->nr] != NULL) && (CopyAtoms[Binder->rightatom->nr] != NULL)) {
916 Log() << Verbose(3) << "Adding Bond between " << *CopyAtoms[Binder->leftatom->nr] << " and " << *CopyAtoms[Binder->rightatom->nr]<< "." << endl;
917 Filling->AddBond(CopyAtoms[Binder->leftatom->nr], CopyAtoms[Binder->rightatom->nr], Binder->BondDegree);
918 }
919 }
[8c54a3]920 }
[bdc91e]921 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
922 delete LCList[*ListRunner];
923 delete TesselStruct[(*ListRunner)];
924 }
[71b20e]925
[357fba]926 return Filling;
[3d919e]927};
[8c54a3]928
[66fd49]929/** Rotates given molecule \a Filling and moves its atoms according to given
930 * \a RandomAtomDisplacement.
931 *
932 * Note that for rotation to be sensible, the molecule should be centered at
933 * the origin. This is not done here!
934 *
935 * \param &Filling molecule whose atoms to displace
936 * \param RandomAtomDisplacement magnitude of random displacement
937 * \param &Rotations 3D rotation matrix (or unity if no rotation desired)
938 */
939void RandomizeMoleculePositions(
940 molecule *&Filling,
941 double RandomAtomDisplacement,
942 RealSpaceMatrix &Rotations
943 )
944{
945 Vector AtomTranslations;
946 for(molecule::iterator miter = Filling->begin(); miter != Filling->end(); ++miter) {
947 Vector temp = (*miter)->getPosition();
948 temp *= Rotations;
949 (*miter)->setPosition(temp);
950 // create atomic random translation vector ...
951 for (int i=0;i<NDIM;i++)
952 AtomTranslations[i] = RandomAtomDisplacement*(rand()/(RAND_MAX/2.) - 1.);
953 (*miter)->setPosition((*miter)->getPosition() + AtomTranslations);
954 }
955}
956
957/** Removes all atoms of a molecule outside.
958 *
959 * If the molecule is empty, it is removed as well.
960 *
961 * @param Filling molecule whose atoms to check, removed if eventually left
962 * empty.
[9df680]963 * @return true - atoms had to be removed, false - no atoms have been removed
[66fd49]964 */
[9df680]965bool RemoveAtomsOutsideDomain(molecule *&Filling)
[66fd49]966{
[9df680]967 bool status = false;
[66fd49]968 Box &Domain = World::getInstance().getDomain();
969 // check if all is still inside domain
970 for(molecule::iterator miter = Filling->begin(); miter != Filling->end(); ) {
971 // check whether each atom is inside box
972 if (!Domain.isInside((*miter)->getPosition())) {
[9df680]973 status = true;
[66fd49]974 atom *Walker = *miter;
975 ++miter;
976 World::getInstance().destroyAtom(Walker);
977 } else {
978 ++miter;
979 }
980 }
981 if (Filling->empty()) {
982 DoLog(0) && (Log() << Verbose(0) << "Removing molecule " << Filling->getName() << ", all atoms have been removed." << std::endl);
983 World::getInstance().destroyMolecule(Filling);
984 }
[9df680]985 return status;
[66fd49]986}
987
988/** Checks whether there are no atoms inside a sphere around \a CurrentPosition
989 * except those atoms present in \a *filler.
990 * If filler is NULL, then we just call LinkedCell::GetPointsInsideSphere() and
991 * check whether the return list is empty.
992 * @param *filler
993 * @param boundary
994 * @param CurrentPosition
995 */
996bool isSpaceAroundPointVoid(
997 LinkedCell *LC,
998 molecule *filler,
999 const double boundary,
1000 Vector &CurrentPosition)
1001{
1002 size_t compareTo = 0;
1003 LinkedCell::LinkedNodes* liste = LC->GetPointsInsideSphere(boundary == 0. ? MYEPSILON : boundary, &CurrentPosition);
1004 if (filler != NULL) {
1005 for (LinkedCell::LinkedNodes::const_iterator iter = liste->begin();
1006 iter != liste->end();
1007 ++iter) {
1008 for (molecule::iterator miter = filler->begin();
1009 miter != filler->end();
1010 ++miter) {
1011 if (*iter == *miter)
1012 ++compareTo;
1013 }
1014 }
1015 }
1016 const bool result = (liste->size() == compareTo);
1017 if (!result) {
1018 DoLog(0) && (Log() << Verbose(0) << "Skipping because of the following atoms:" << std::endl);
1019 for (LinkedCell::LinkedNodes::const_iterator iter = liste->begin();
1020 iter != liste->end();
1021 ++iter) {
1022 DoLog(0) && (Log() << Verbose(0) << **iter << std::endl);
1023 }
1024 }
1025 delete(liste);
1026 return result;
1027}
1028
1029/** Fills the empty space of the simulation box with water.
[eee966]1030 * \param *filler molecule which the box is to be filled with
1031 * \param configuration contains box dimensions
1032 * \param distance[NDIM] distance between filling molecules in each direction
[66fd49]1033 * \param boundary length of boundary zone between molecule and filling molecules
[eee966]1034 * \param RandAtomDisplacement maximum distance for random displacement per atom
1035 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
[66fd49]1036 * \param MinDistance minimum distance to boundary of domain and present molecules
1037 * \param DoRandomRotation true - do random rotations, false - don't
[eee966]1038 */
[66fd49]1039void FillVoidWithMolecule(
1040 molecule *&filler,
1041 config &configuration,
1042 const double distance[NDIM],
1043 const double boundary,
1044 const double RandomAtomDisplacement,
1045 const double RandomMolDisplacement,
1046 const double MinDistance,
1047 const bool DoRandomRotation
1048 )
[eee966]1049{
1050 Info FunctionInfo(__func__);
1051 molecule *Filling = NULL;
1052 Vector CurrentPosition;
1053 int N[NDIM];
1054 int n[NDIM];
[cca9ef]1055 const RealSpaceMatrix &M = World::getInstance().getDomain().getM();
1056 RealSpaceMatrix Rotations;
1057 const RealSpaceMatrix &MInverse = World::getInstance().getDomain().getMinv();
[eee966]1058 Vector FillerTranslations;
1059 Vector FillerDistance;
1060 Vector Inserter;
1061 double FillIt = false;
[66fd49]1062 Vector firstInserter;
1063 bool firstInsertion = true;
1064 const Box &Domain = World::getInstance().getDomain();
[eee966]1065 map<molecule *, LinkedCell *> LCList;
1066 std::vector<molecule *> List = World::getInstance().getAllMolecules();
1067 MoleculeListClass *MolList = World::getInstance().getMolecules();
1068
1069 for (std::vector<molecule *>::iterator ListRunner = List.begin(); ListRunner != List.end(); ListRunner++)
1070 if ((*ListRunner)->getAtomCount() > 0) {
1071 DoLog(1) && (Log() << Verbose(1) << "Pre-creating linked cell lists for molecule " << *ListRunner << "." << endl);
1072 LCList[(*ListRunner)] = new LinkedCell(*(*ListRunner), 10.); // get linked cell list
1073 }
1074
[9df680]1075 // Center filler at its center of gravity
1076 Vector *gravity = filler->DetermineCenterOfGravity();
1077 filler->CenterAtVector(gravity);
1078 delete gravity;
[66fd49]1079 //const int FillerCount = filler->getAtomCount();
[eee966]1080 DoLog(2) && (Log() << Verbose(2) << "INFO: Filler molecule has the following bonds:" << endl);
1081 for(molecule::iterator AtomRunner = filler->begin(); AtomRunner != filler->end(); ++AtomRunner)
1082 for(BondList::iterator BondRunner = (*AtomRunner)->ListOfBonds.begin(); BondRunner != (*AtomRunner)->ListOfBonds.end(); ++BondRunner)
1083 if ((*BondRunner)->leftatom == *AtomRunner)
1084 DoLog(2) && (Log() << Verbose(2) << " " << *(*BondRunner) << endl);
1085
1086 // calculate filler grid in [0,1]^3
1087 FillerDistance = MInverse * Vector(distance[0], distance[1], distance[2]);
1088 for(int i=0;i<NDIM;i++)
1089 N[i] = (int) ceil(1./FillerDistance[i]);
1090 DoLog(1) && (Log() << Verbose(1) << "INFO: Grid steps are " << N[0] << ", " << N[1] << ", " << N[2] << "." << endl);
1091
1092 // initialize seed of random number generator to current time
1093 srand ( time(NULL) );
1094
1095 // go over [0,1]^3 filler grid
1096 for (n[0] = 0; n[0] < N[0]; n[0]++)
1097 for (n[1] = 0; n[1] < N[1]; n[1]++)
1098 for (n[2] = 0; n[2] < N[2]; n[2]++) {
1099 // calculate position of current grid vector in untransformed box
1100 CurrentPosition = M * Vector((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
1101 // create molecule random translation vector ...
1102 for (int i=0;i<NDIM;i++)
1103 FillerTranslations[i] = RandomMolDisplacement*(rand()/(RAND_MAX/2.) - 1.);
1104 DoLog(2) && (Log() << Verbose(2) << "INFO: Current Position is " << CurrentPosition << "+" << FillerTranslations << "." << endl);
1105
1106 // ... and rotation matrix
[66fd49]1107 if (DoRandomRotation)
1108 Rotations.setRandomRotation();
1109 else
1110 Rotations.setIdentity();
[eee966]1111
1112
[66fd49]1113 // Check whether there is anything too close by and whether atom is outside of domain
[eee966]1114 FillIt = true;
[66fd49]1115 for (std::map<molecule *, LinkedCell *>::iterator ListRunner = LCList.begin(); ListRunner != LCList.end(); ++ListRunner) {
1116 FillIt = FillIt && isSpaceAroundPointVoid(
1117 ListRunner->second,
1118 (firstInsertion ? filler : NULL),
1119 boundary,
1120 CurrentPosition);
1121 FillIt = FillIt && (Domain.isInside(CurrentPosition))
1122 && ((Domain.DistanceToBoundary(CurrentPosition) - MinDistance) > -MYEPSILON);
1123 if (!FillIt)
1124 break;
[eee966]1125 }
[66fd49]1126
[eee966]1127 // insert into Filling
1128 if (FillIt) {
1129 Inserter = CurrentPosition + FillerTranslations;
1130 DoLog(1) && (Log() << Verbose(1) << "INFO: Position at " << Inserter << " is void point." << endl);
[66fd49]1131 // fill!
[9df680]1132 Filling = filler->CopyMolecule();
1133 RandomizeMoleculePositions(Filling, RandomAtomDisplacement, Rotations);
1134 // translation
1135 Filling->Translate(&Inserter);
1136 // remove out-of-bounds atoms
1137 const bool status = RemoveAtomsOutsideDomain(Filling);
1138 if ((firstInsertion) && (!status)) { // no atom has been removed
1139 // remove copied atoms and molecule again
1140 Filling->removeAtomsinMolecule();
1141 World::getInstance().destroyMolecule(Filling);
1142 // and mark is final filler position
[66fd49]1143 Filling = filler;
1144 firstInsertion = false;
1145 firstInserter = Inserter;
[9df680]1146 } else {
[66fd49]1147 // TODO: Remove when World has no MoleculeListClass anymore
1148 MolList->insert(Filling);
[eee966]1149 }
1150 } else {
[9df680]1151 DoLog(1) && (Log() << Verbose(1) << "INFO: Position at " << Inserter << " is non-void point, within boundary or outside of MaxDistance." << endl);
[eee966]1152 continue;
1153 }
1154 }
[66fd49]1155
1156 // have we inserted any molecules?
1157 if (firstInsertion) {
1158 // If not remove filler
1159 for(molecule::iterator miter = filler->begin(); !filler->empty(); miter = filler->begin()) {
1160 atom *Walker = *miter;
1161 filler->erase(Walker);
1162 World::getInstance().destroyAtom(Walker);
1163 }
1164 World::getInstance().destroyMolecule(filler);
1165 } else {
1166 // otherwise translate and randomize to final position
1167 if (DoRandomRotation)
1168 Rotations.setRandomRotation();
1169 else
1170 Rotations.setIdentity();
1171 RandomizeMoleculePositions(filler, RandomAtomDisplacement, Rotations);
1172 // translation
1173 filler->Translate(&firstInserter);
1174 // remove out-of-bounds atoms
1175 RemoveAtomsOutsideDomain(filler);
[eee966]1176 }
[66fd49]1177
1178 DoLog(0) && (Log() << Verbose(0) << MolList->ListOfMolecules.size() << " molecules have been inserted." << std::endl);
[eee966]1179
1180 for (std::map<molecule *, LinkedCell *>::iterator ListRunner = LCList.begin(); !LCList.empty(); ListRunner = LCList.begin()) {
1181 delete ListRunner->second;
1182 LCList.erase(ListRunner);
1183 }
1184};
[8c54a3]1185
[6ac7ee]1186/** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
1187 * \param *out output stream for debugging
1188 * \param *mol molecule structure with Atom's and Bond's
[776b64]1189 * \param *&TesselStruct Tesselation filled with points, lines and triangles on boundary on return
1190 * \param *&LCList atoms in LinkedCell list
[57066a]1191 * \param RADIUS radius of the virtual sphere
[6ac7ee]1192 * \param *filename filename prefix for output of vertex data
[4fc93f]1193 * \return true - tesselation successful, false - tesselation failed
[6ac7ee]1194 */
[4fc93f]1195bool FindNonConvexBorder(const molecule* const mol, Tesselation *&TesselStruct, const LinkedCell *&LCList, const double RADIUS, const char *filename = NULL)
[03648b]1196{
[f67b6e]1197 Info FunctionInfo(__func__);
[3d919e]1198 bool freeLC = false;
[4fc93f]1199 bool status = false;
[6613ec]1200 CandidateForTesselation *baseline = NULL;
[1e168b]1201 bool OneLoopWithoutSuccessFlag = true; // marks whether we went once through all baselines without finding any without two triangles
[ad37ab]1202 bool TesselationFailFlag = false;
[357fba]1203
[a7b761b]1204 mol->getAtomCount();
[357fba]1205
[776b64]1206 if (TesselStruct == NULL) {
[a67d19]1207 DoLog(1) && (Log() << Verbose(1) << "Allocating Tesselation struct ..." << endl);
[776b64]1208 TesselStruct= new Tesselation;
[ef0e6d]1209 } else {
[776b64]1210 delete(TesselStruct);
[a67d19]1211 DoLog(1) && (Log() << Verbose(1) << "Re-Allocating Tesselation struct ..." << endl);
[776b64]1212 TesselStruct = new Tesselation;
[3d919e]1213 }
[ad37ab]1214
[57066a]1215 // initialise Linked Cell
[3d919e]1216 if (LCList == NULL) {
[af2c424]1217 LCList = new LinkedCell(*mol, 2.*RADIUS);
[3d919e]1218 freeLC = true;
1219 }
1220
[57066a]1221 // 1. get starting triangle
[ce70970]1222 if (!TesselStruct->FindStartingTriangle(RADIUS, LCList)) {
1223 DoeLog(0) && (eLog() << Verbose(0) << "No valid starting triangle found." << endl);
[b5c2d7]1224 //performCriticalExit();
[ce70970]1225 }
[f8bd7d]1226 if (filename != NULL) {
1227 if ((DoSingleStepOutput && ((TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
1228 TesselStruct->Output(filename, mol);
1229 }
1230 }
[3d919e]1231
[57066a]1232 // 2. expand from there
[1e168b]1233 while ((!TesselStruct->OpenLines.empty()) && (OneLoopWithoutSuccessFlag)) {
[b40a93]1234 (cerr << "There are " << TesselStruct->TrianglesOnBoundary.size() << " triangles and " << TesselStruct->OpenLines.size() << " open lines to scan for candidates." << endl);
1235 // 2a. print OpenLines without candidates
1236 DoLog(1) && (Log() << Verbose(1) << "There are the following open lines to scan for a candidates:" << endl);
[1e168b]1237 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
[b40a93]1238 if (Runner->second->pointlist.empty())
1239 DoLog(1) && (Log() << Verbose(1) << " " << *(Runner->second) << endl);
[1e168b]1240
[734816]1241 // 2b. find best candidate for each OpenLine
[6613ec]1242 TesselationFailFlag = TesselStruct->FindCandidatesforOpenLines(RADIUS, LCList);
[3d919e]1243
[734816]1244 // 2c. print OpenLines with candidates again
[a67d19]1245 DoLog(1) && (Log() << Verbose(1) << "There are " << TesselStruct->OpenLines.size() << " open lines to scan for the best candidates:" << endl);
[1e168b]1246 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
[a67d19]1247 DoLog(1) && (Log() << Verbose(1) << " " << *(Runner->second) << endl);
[1e168b]1248
[734816]1249 // 2d. search for smallest ShortestAngle among all candidates
1250 double ShortestAngle = 4.*M_PI;
[1e168b]1251 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++) {
1252 if (Runner->second->ShortestAngle < ShortestAngle) {
1253 baseline = Runner->second;
1254 ShortestAngle = baseline->ShortestAngle;
[a67d19]1255 DoLog(1) && (Log() << Verbose(1) << "New best candidate is " << *baseline->BaseLine << " with point " << *(*baseline->pointlist.begin()) << " and angle " << baseline->ShortestAngle << endl);
[1e168b]1256 }
1257 }
[734816]1258 // 2e. if we found one, add candidate
[f67b6e]1259 if ((ShortestAngle == 4.*M_PI) || (baseline->pointlist.empty()))
[7dea7c]1260 OneLoopWithoutSuccessFlag = false;
[1e168b]1261 else {
[474961]1262 TesselStruct->AddCandidatePolygon(*baseline, RADIUS, LCList);
[1e168b]1263 }
1264
[734816]1265 // 2f. write temporary envelope
[1e168b]1266 if (filename != NULL) {
1267 if ((DoSingleStepOutput && ((TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
1268 TesselStruct->Output(filename, mol);
1269 }
[3d919e]1270 }
1271 }
[4fc93f]1272// // check envelope for consistency
1273// status = CheckListOfBaselines(TesselStruct);
1274//
1275// // look whether all points are inside of the convex envelope, otherwise add them via degenerated triangles
1276// //->InsertStraddlingPoints(mol, LCList);
[9879f6]1277// for (molecule::const_iterator iter = mol->begin(); iter != mol->end(); ++iter) {
[57066a]1278// class TesselPoint *Runner = NULL;
[9879f6]1279// Runner = *iter;
[e138de]1280// Log() << Verbose(1) << "Checking on " << Runner->Name << " ... " << endl;
1281// if (!->IsInnerPoint(Runner, LCList)) {
1282// Log() << Verbose(2) << Runner->Name << " is outside of envelope, adding via degenerated triangles." << endl;
1283// ->AddBoundaryPointByDegeneratedTriangle(Runner, LCList);
[57066a]1284// } else {
[e138de]1285// Log() << Verbose(2) << Runner->Name << " is inside of or on envelope." << endl;
[57066a]1286// }
1287// }
[357fba]1288
[f67b6e]1289// // Purges surplus triangles.
1290// TesselStruct->RemoveDegeneratedTriangles();
[b32dbb]1291//
1292// // check envelope for consistency
1293// status = CheckListOfBaselines(TesselStruct);
[b998c3]1294
[c72112]1295 cout << "before correction" << endl;
1296
[b998c3]1297 // store before correction
[c72112]1298 StoreTrianglesinFile(mol, TesselStruct, filename, "");
[b998c3]1299
[6613ec]1300// // correct degenerated polygons
1301// TesselStruct->CorrectAllDegeneratedPolygons();
1302//
1303// // check envelope for consistency
1304// status = CheckListOfBaselines(TesselStruct);
[ef0e6d]1305
[57066a]1306 // write final envelope
[e138de]1307 CalculateConcavityPerBoundaryPoint(TesselStruct);
[c72112]1308 cout << "after correction" << endl;
1309 StoreTrianglesinFile(mol, TesselStruct, filename, "");
[8c54a3]1310
[3d919e]1311 if (freeLC)
1312 delete(LCList);
[4fc93f]1313
1314 return status;
[6ac7ee]1315};
[03648b]1316
[57066a]1317
[ad37ab]1318/** Finds a hole of sufficient size in \a *mols to embed \a *srcmol into it.
[ca2587]1319 * \param *out output stream for debugging
[ad37ab]1320 * \param *mols molecules in the domain to embed in between
1321 * \param *srcmol embedding molecule
[ca2587]1322 * \return *Vector new center of \a *srcmol for embedding relative to \a this
1323 */
[e138de]1324Vector* FindEmbeddingHole(MoleculeListClass *mols, molecule *srcmol)
[ca2587]1325{
[f67b6e]1326 Info FunctionInfo(__func__);
[ca2587]1327 Vector *Center = new Vector;
1328 Center->Zero();
1329 // calculate volume/shape of \a *srcmol
1330
1331 // find embedding holes
1332
1333 // if more than one, let user choose
1334
1335 // return embedding center
1336 return Center;
1337};
1338
Note: See TracBrowser for help on using the repository browser.