source: src/boundary.cpp@ b8c9d8

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 b8c9d8 was b5c2d7, checked in by Frederik Heber <heber@…>, 15 years ago

Don't exit when no starting triangle has been found.

  • The issue is that this is not a bug, but just a limitation of the so-far employed algorithm for obtaining a starting triangle.
  • If we exit, no .dat file is written, not even an empty one, indicating a perpetual running of the routine, which it does not.

Signed-off-by: Frederik Heber <heber@…>

  • Property mode set to 100644
File size: 51.3 KB
RevLine 
[f66195]1/** \file boundary.cpp
[edb93c]2 *
3 * Implementations and super-function for envelopes
[2319ed]4 */
5
[f66195]6#include "atom.hpp"
7#include "bond.hpp"
[8eb17a]8#include "boundary.hpp"
[f66195]9#include "config.hpp"
10#include "element.hpp"
11#include "helpers.hpp"
[f67b6e]12#include "info.hpp"
[f66195]13#include "linkedcell.hpp"
[e138de]14#include "log.hpp"
[29812d]15#include "memoryallocator.hpp"
[f66195]16#include "molecule.hpp"
17#include "tesselation.hpp"
18#include "tesselationhelpers.hpp"
[b34306]19#include "World.hpp"
[2319ed]20
[357fba]21#include<gsl/gsl_poly.h>
[d6eb80]22#include<time.h>
[2319ed]23
[357fba]24// ========================================== F U N C T I O N S =================================
[2319ed]25
26
[357fba]27/** Determines greatest diameters of a cluster defined by its convex envelope.
28 * Looks at lines parallel to one axis and where they intersect on the projected planes
[2319ed]29 * \param *out output stream for debugging
[357fba]30 * \param *BoundaryPoints NDIM set of boundary points defining the convex envelope on each projected plane
31 * \param *mol molecule structure representing the cluster
[776b64]32 * \param *&TesselStruct Tesselation structure with triangles
[357fba]33 * \param IsAngstroem whether we have angstroem or atomic units
34 * \return NDIM array of the diameters
[e4ea46]35 */
[e138de]36double *GetDiametersOfCluster(const Boundaries *BoundaryPtr, const molecule *mol, Tesselation *&TesselStruct, const bool IsAngstroem)
[caf5d6]37{
[f67b6e]38 Info FunctionInfo(__func__);
[357fba]39 // get points on boundary of NULL was given as parameter
40 bool BoundaryFreeFlag = false;
[ad37ab]41 double OldComponent = 0.;
42 double tmp = 0.;
43 double w1 = 0.;
44 double w2 = 0.;
45 Vector DistanceVector;
46 Vector OtherVector;
47 int component = 0;
48 int Othercomponent = 0;
[776b64]49 Boundaries::const_iterator Neighbour;
50 Boundaries::const_iterator OtherNeighbour;
[ad37ab]51 double *GreatestDiameter = new double[NDIM];
52
[776b64]53 const Boundaries *BoundaryPoints;
54 if (BoundaryPtr == NULL) {
[357fba]55 BoundaryFreeFlag = true;
[e138de]56 BoundaryPoints = GetBoundaryPoints(mol, TesselStruct);
[86234b]57 } else {
[776b64]58 BoundaryPoints = BoundaryPtr;
[a67d19]59 DoLog(0) && (Log() << Verbose(0) << "Using given boundary points set." << endl);
[86234b]60 }
[357fba]61 // determine biggest "diameter" of cluster for each axis
62 for (int i = 0; i < NDIM; i++)
63 GreatestDiameter[i] = 0.;
64 for (int axis = 0; axis < NDIM; axis++)
65 { // regard each projected plane
[e138de]66 //Log() << Verbose(1) << "Current axis is " << axis << "." << endl;
[357fba]67 for (int j = 0; j < 2; j++)
68 { // and for both axis on the current plane
69 component = (axis + j + 1) % NDIM;
70 Othercomponent = (axis + 1 + ((j + 1) & 1)) % NDIM;
[e138de]71 //Log() << Verbose(1) << "Current component is " << component << ", Othercomponent is " << Othercomponent << "." << endl;
[776b64]72 for (Boundaries::const_iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
[f67b6e]73 //Log() << Verbose(1) << "Current runner is " << *(runner->second.second) << "." << endl;
[357fba]74 // seek for the neighbours pair where the Othercomponent sign flips
75 Neighbour = runner;
76 Neighbour++;
77 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
78 Neighbour = BoundaryPoints[axis].begin();
79 DistanceVector.CopyVector(&runner->second.second->x);
80 DistanceVector.SubtractVector(&Neighbour->second.second->x);
[776b64]81 do { // seek for neighbour pair where it flips
[357fba]82 OldComponent = DistanceVector.x[Othercomponent];
83 Neighbour++;
84 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
85 Neighbour = BoundaryPoints[axis].begin();
86 DistanceVector.CopyVector(&runner->second.second->x);
87 DistanceVector.SubtractVector(&Neighbour->second.second->x);
[f67b6e]88 //Log() << Verbose(2) << "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << "." << endl;
[776b64]89 } while ((runner != Neighbour) && (fabs(OldComponent / fabs(
[357fba]90 OldComponent) - DistanceVector.x[Othercomponent] / fabs(
91 DistanceVector.x[Othercomponent])) < MYEPSILON)); // as long as sign does not flip
[776b64]92 if (runner != Neighbour) {
[357fba]93 OtherNeighbour = Neighbour;
94 if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around
95 OtherNeighbour = BoundaryPoints[axis].end();
96 OtherNeighbour--;
[f67b6e]97 //Log() << Verbose(1) << "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << "." << endl;
[357fba]98 // now we have found the pair: Neighbour and OtherNeighbour
99 OtherVector.CopyVector(&runner->second.second->x);
100 OtherVector.SubtractVector(&OtherNeighbour->second.second->x);
[f67b6e]101 //Log() << Verbose(1) << "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << "." << endl;
102 //Log() << Verbose(1) << "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << "." << endl;
[357fba]103 // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour
104 w1 = fabs(OtherVector.x[Othercomponent]);
105 w2 = fabs(DistanceVector.x[Othercomponent]);
106 tmp = fabs((w1 * DistanceVector.x[component] + w2
107 * OtherVector.x[component]) / (w1 + w2));
108 // mark if it has greater diameter
[f67b6e]109 //Log() << Verbose(1) << "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << "." << endl;
[357fba]110 GreatestDiameter[component] = (GreatestDiameter[component]
111 > tmp) ? GreatestDiameter[component] : tmp;
112 } //else
[f67b6e]113 //Log() << Verbose(1) << "Saw no sign flip, probably top or bottom node." << endl;
[3d919e]114 }
115 }
116 }
[e138de]117 Log() << Verbose(0) << "RESULT: The biggest diameters are "
[357fba]118 << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and "
119 << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom"
120 : "atomiclength") << "." << endl;
[03648b]121
[357fba]122 // free reference lists
123 if (BoundaryFreeFlag)
124 delete[] (BoundaryPoints);
[e4ea46]125
[357fba]126 return GreatestDiameter;
[e4ea46]127}
128;
[03648b]129
[042f82]130
[357fba]131/** Determines the boundary points of a cluster.
132 * Does a projection per axis onto the orthogonal plane, transforms into spherical coordinates, sorts them by the angle
133 * and looks at triples: if the middle has less a distance than the allowed maximum height of the triangle formed by the plane's
134 * center and first and last point in the triple, it is thrown out.
135 * \param *out output stream for debugging
136 * \param *mol molecule structure representing the cluster
[776b64]137 * \param *&TesselStruct pointer to Tesselation structure
[e4ea46]138 */
[e138de]139Boundaries *GetBoundaryPoints(const molecule *mol, Tesselation *&TesselStruct)
[caf5d6]140{
[f67b6e]141 Info FunctionInfo(__func__);
[357fba]142 atom *Walker = NULL;
143 PointMap PointsOnBoundary;
144 LineMap LinesOnBoundary;
145 TriangleMap TrianglesOnBoundary;
[e138de]146 Vector *MolCenter = mol->DetermineCenterOfAll();
[357fba]147 Vector helper;
[ad37ab]148 BoundariesTestPair BoundaryTestPair;
149 Vector AxisVector;
150 Vector AngleReferenceVector;
151 Vector AngleReferenceNormalVector;
152 Vector ProjectedVector;
153 Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, nr)
154 double angle = 0.;
[042f82]155
[357fba]156 // 3a. Go through every axis
157 for (int axis = 0; axis < NDIM; axis++) {
158 AxisVector.Zero();
159 AngleReferenceVector.Zero();
160 AngleReferenceNormalVector.Zero();
161 AxisVector.x[axis] = 1.;
162 AngleReferenceVector.x[(axis + 1) % NDIM] = 1.;
163 AngleReferenceNormalVector.x[(axis + 2) % NDIM] = 1.;
[042f82]164
[a67d19]165 DoLog(1) && (Log() << Verbose(1) << "Axisvector is " << AxisVector << " and AngleReferenceVector is " << AngleReferenceVector << ", and AngleReferenceNormalVector is " << AngleReferenceNormalVector << "." << endl);
[042f82]166
[357fba]167 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
168 Walker = mol->start;
169 while (Walker->next != mol->end) {
170 Walker = Walker->next;
171 ProjectedVector.CopyVector(&Walker->x);
172 ProjectedVector.SubtractVector(MolCenter);
173 ProjectedVector.ProjectOntoPlane(&AxisVector);
[042f82]174
[357fba]175 // correct for negative side
[776b64]176 const double radius = ProjectedVector.NormSquared();
[357fba]177 if (fabs(radius) > MYEPSILON)
178 angle = ProjectedVector.Angle(&AngleReferenceVector);
179 else
180 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
[042f82]181
[f67b6e]182 //Log() << Verbose(1) << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl;
[658efb]183 if (ProjectedVector.ScalarProduct(&AngleReferenceNormalVector) > 0) {
[357fba]184 angle = 2. * M_PI - angle;
185 }
[a67d19]186 DoLog(1) && (Log() << Verbose(1) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): " << ProjectedVector << endl);
[357fba]187 BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle, DistancePair (radius, Walker)));
188 if (!BoundaryTestPair.second) { // same point exists, check first r, then distance of original vectors to center of gravity
[a67d19]189 DoLog(2) && (Log() << Verbose(2) << "Encountered two vectors whose projection onto axis " << axis << " is equal: " << endl);
190 DoLog(2) && (Log() << Verbose(2) << "Present vector: " << *BoundaryTestPair.first->second.second << endl);
191 DoLog(2) && (Log() << Verbose(2) << "New vector: " << *Walker << endl);
[776b64]192 const double ProjectedVectorNorm = ProjectedVector.NormSquared();
193 if ((ProjectedVectorNorm - BoundaryTestPair.first->second.first) > MYEPSILON) {
194 BoundaryTestPair.first->second.first = ProjectedVectorNorm;
[357fba]195 BoundaryTestPair.first->second.second = Walker;
[a67d19]196 DoLog(2) && (Log() << Verbose(2) << "Keeping new vector due to larger projected distance " << ProjectedVectorNorm << "." << endl);
[776b64]197 } else if (fabs(ProjectedVectorNorm - BoundaryTestPair.first->second.first) < MYEPSILON) {
[357fba]198 helper.CopyVector(&Walker->x);
199 helper.SubtractVector(MolCenter);
[776b64]200 const double oldhelperNorm = helper.NormSquared();
[357fba]201 helper.CopyVector(&BoundaryTestPair.first->second.second->x);
202 helper.SubtractVector(MolCenter);
[776b64]203 if (helper.NormSquared() < oldhelperNorm) {
[357fba]204 BoundaryTestPair.first->second.second = Walker;
[a67d19]205 DoLog(2) && (Log() << Verbose(2) << "Keeping new vector due to larger distance to molecule center " << helper.NormSquared() << "." << endl);
[357fba]206 } else {
[a67d19]207 DoLog(2) && (Log() << Verbose(2) << "Keeping present vector due to larger distance to molecule center " << oldhelperNorm << "." << endl);
[357fba]208 }
209 } else {
[a67d19]210 DoLog(2) && (Log() << Verbose(2) << "Keeping present vector due to larger projected distance " << ProjectedVectorNorm << "." << endl);
[357fba]211 }
[018741]212 }
[3d919e]213 }
[357fba]214 // printing all inserted for debugging
215 // {
[f67b6e]216 // Log() << Verbose(1) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
[357fba]217 // int i=0;
218 // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
219 // if (runner != BoundaryPoints[axis].begin())
[f67b6e]220 // Log() << Verbose(0) << ", " << i << ": " << *runner->second.second;
[357fba]221 // else
[f67b6e]222 // Log() << Verbose(0) << i << ": " << *runner->second.second;
[357fba]223 // i++;
224 // }
[f67b6e]225 // Log() << Verbose(0) << endl;
[357fba]226 // }
227 // 3c. throw out points whose distance is less than the mean of left and right neighbours
228 bool flag = false;
[a67d19]229 DoLog(1) && (Log() << Verbose(1) << "Looking for candidates to kick out by convex condition ... " << endl);
[357fba]230 do { // do as long as we still throw one out per round
231 flag = false;
232 Boundaries::iterator left = BoundaryPoints[axis].end();
233 Boundaries::iterator right = BoundaryPoints[axis].end();
234 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
235 // set neighbours correctly
236 if (runner == BoundaryPoints[axis].begin()) {
237 left = BoundaryPoints[axis].end();
238 } else {
239 left = runner;
240 }
241 left--;
242 right = runner;
243 right++;
244 if (right == BoundaryPoints[axis].end()) {
245 right = BoundaryPoints[axis].begin();
246 }
247 // check distance
[3d919e]248
[357fba]249 // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)
250 {
251 Vector SideA, SideB, SideC, SideH;
252 SideA.CopyVector(&left->second.second->x);
253 SideA.SubtractVector(MolCenter);
254 SideA.ProjectOntoPlane(&AxisVector);
[f67b6e]255 // Log() << Verbose(1) << "SideA: " << SideA << endl;
[3d919e]256
[357fba]257 SideB.CopyVector(&right->second.second->x);
258 SideB.SubtractVector(MolCenter);
259 SideB.ProjectOntoPlane(&AxisVector);
[f67b6e]260 // Log() << Verbose(1) << "SideB: " << SideB << endl;
[3d919e]261
[357fba]262 SideC.CopyVector(&left->second.second->x);
263 SideC.SubtractVector(&right->second.second->x);
264 SideC.ProjectOntoPlane(&AxisVector);
[f67b6e]265 // Log() << Verbose(1) << "SideC: " << SideC << endl;
[3d919e]266
[357fba]267 SideH.CopyVector(&runner->second.second->x);
268 SideH.SubtractVector(MolCenter);
269 SideH.ProjectOntoPlane(&AxisVector);
[f67b6e]270 // Log() << Verbose(1) << "SideH: " << SideH << endl;
[3d919e]271
[357fba]272 // calculate each length
[ad37ab]273 const double a = SideA.Norm();
274 //const double b = SideB.Norm();
275 //const double c = SideC.Norm();
276 const double h = SideH.Norm();
[357fba]277 // calculate the angles
[ad37ab]278 const double alpha = SideA.Angle(&SideH);
279 const double beta = SideA.Angle(&SideC);
280 const double gamma = SideB.Angle(&SideH);
281 const double delta = SideC.Angle(&SideH);
282 const double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.);
[f67b6e]283 //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]284 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]285 if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance)) < MYEPSILON) && ((h - MinDistance)) < -MYEPSILON) {
286 // throw out point
[a67d19]287 DoLog(1) && (Log() << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl);
[357fba]288 BoundaryPoints[axis].erase(runner);
289 flag = true;
[3d919e]290 }
291 }
292 }
[357fba]293 } while (flag);
[3d919e]294 }
[357fba]295 delete(MolCenter);
296 return BoundaryPoints;
[6ac7ee]297};
298
[357fba]299/** Tesselates the convex boundary by finding all boundary points.
300 * \param *out output stream for debugging
[776b64]301 * \param *mol molecule structure with Atom's and Bond's.
[357fba]302 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
303 * \param *LCList atoms in LinkedCell list
304 * \param *filename filename prefix for output of vertex data
305 * \return *TesselStruct is filled with convex boundary and tesselation is stored under \a *filename.
[6ac7ee]306 */
[e138de]307void FindConvexBorder(const molecule* mol, Tesselation *&TesselStruct, const LinkedCell *LCList, const char *filename)
[6ac7ee]308{
[f67b6e]309 Info FunctionInfo(__func__);
[357fba]310 bool BoundaryFreeFlag = false;
311 Boundaries *BoundaryPoints = NULL;
[3d919e]312
[776b64]313 if (TesselStruct != NULL) // free if allocated
314 delete(TesselStruct);
315 TesselStruct = new class Tesselation;
[3d919e]316
[357fba]317 // 1. Find all points on the boundary
318 if (BoundaryPoints == NULL) {
319 BoundaryFreeFlag = true;
[e138de]320 BoundaryPoints = GetBoundaryPoints(mol, TesselStruct);
[357fba]321 } else {
[a67d19]322 DoLog(0) && (Log() << Verbose(0) << "Using given boundary points set." << endl);
[3d919e]323 }
324
[357fba]325// printing all inserted for debugging
326 for (int axis=0; axis < NDIM; axis++)
327 {
[a67d19]328 DoLog(1) && (Log() << Verbose(1) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl);
[357fba]329 int i=0;
330 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
331 if (runner != BoundaryPoints[axis].begin())
[a67d19]332 DoLog(0) && (Log() << Verbose(0) << ", " << i << ": " << *runner->second.second);
[357fba]333 else
[a67d19]334 DoLog(0) && (Log() << Verbose(0) << i << ": " << *runner->second.second);
[357fba]335 i++;
[a37350]336 }
[a67d19]337 DoLog(0) && (Log() << Verbose(0) << endl);
[a37350]338 }
[3d919e]339
[357fba]340 // 2. fill the boundary point list
341 for (int axis = 0; axis < NDIM; axis++)
342 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++)
[776b64]343 if (!TesselStruct->AddBoundaryPoint(runner->second.second, 0))
[58ed4a]344 DoeLog(2) && (eLog()<< Verbose(2) << "Point " << *(runner->second.second) << " is already present!" << endl);
[e4ea46]345
[a67d19]346 DoLog(0) && (Log() << Verbose(0) << "I found " << TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl);
[357fba]347 // now we have the whole set of edge points in the BoundaryList
[018741]348
[357fba]349 // listing for debugging
[e138de]350 // Log() << Verbose(1) << "Listing PointsOnBoundary:";
[357fba]351 // for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
[f67b6e]352 // Log() << Verbose(0) << " " << *runner->second;
[357fba]353 // }
[f67b6e]354 // Log() << Verbose(0) << endl;
[018741]355
[357fba]356 // 3a. guess starting triangle
[e138de]357 TesselStruct->GuessStartingTriangle();
[018741]358
[357fba]359 // 3b. go through all lines, that are not yet part of two triangles (only of one so far)
[e138de]360 TesselStruct->TesselateOnBoundary(mol);
[3d919e]361
[357fba]362 // 3c. check whether all atoms lay inside the boundary, if not, add to boundary points, segment triangle into three with the new point
[e138de]363 if (!TesselStruct->InsertStraddlingPoints(mol, LCList))
[58ed4a]364 DoeLog(1) && (eLog()<< Verbose(1) << "Insertion of straddling points failed!" << endl);
[3d919e]365
[a67d19]366 DoLog(0) && (Log() << Verbose(0) << "I created " << TesselStruct->TrianglesOnBoundary.size() << " intermediate triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points." << endl);
[ef0e6d]367
368 // 4. Store triangles in tecplot file
369 if (filename != NULL) {
370 if (DoTecplotOutput) {
371 string OutputName(filename);
372 OutputName.append("_intermed");
373 OutputName.append(TecplotSuffix);
374 ofstream *tecplot = new ofstream(OutputName.c_str());
[e138de]375 WriteTecplotFile(tecplot, TesselStruct, mol, 0);
[ef0e6d]376 tecplot->close();
377 delete(tecplot);
378 }
379 if (DoRaster3DOutput) {
380 string OutputName(filename);
381 OutputName.append("_intermed");
382 OutputName.append(Raster3DSuffix);
383 ofstream *rasterplot = new ofstream(OutputName.c_str());
[e138de]384 WriteRaster3dFile(rasterplot, TesselStruct, mol);
[ef0e6d]385 rasterplot->close();
386 delete(rasterplot);
387 }
388 }
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);
[57066a]407 }
[093645]408 }
409 }
410 } while (!AllConvex);
[3d919e]411
[ef0e6d]412 // 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]413// if (!TesselStruct->CorrectConcaveTesselPoints(out))
[e138de]414// Log() << Verbose(1) << "Correction of concave tesselpoints failed!" << endl;
[ef0e6d]415
[a67d19]416 DoLog(0) && (Log() << Verbose(0) << "I created " << TesselStruct->TrianglesOnBoundary.size() << " triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points." << endl);
[3d919e]417
[357fba]418 // 4. Store triangles in tecplot file
419 if (filename != NULL) {
420 if (DoTecplotOutput) {
421 string OutputName(filename);
422 OutputName.append(TecplotSuffix);
423 ofstream *tecplot = new ofstream(OutputName.c_str());
[e138de]424 WriteTecplotFile(tecplot, TesselStruct, mol, 0);
[357fba]425 tecplot->close();
426 delete(tecplot);
[3d919e]427 }
[357fba]428 if (DoRaster3DOutput) {
429 string OutputName(filename);
430 OutputName.append(Raster3DSuffix);
431 ofstream *rasterplot = new ofstream(OutputName.c_str());
[e138de]432 WriteRaster3dFile(rasterplot, TesselStruct, mol);
[357fba]433 rasterplot->close();
434 delete(rasterplot);
[042f82]435 }
[3d919e]436 }
437
[ef0e6d]438
[357fba]439 // free reference lists
440 if (BoundaryFreeFlag)
441 delete[] (BoundaryPoints);
[3d919e]442};
[6ac7ee]443
[d4fa23]444/** For testing removes one boundary point after another to check for leaks.
445 * \param *out output stream for debugging
446 * \param *TesselStruct Tesselation containing envelope with boundary points
447 * \param *mol molecule
448 * \param *filename name of file
449 * \return true - all removed, false - something went wrong
450 */
[e138de]451bool RemoveAllBoundaryPoints(class Tesselation *&TesselStruct, const molecule * const mol, const char * const filename)
[d4fa23]452{
[f67b6e]453 Info FunctionInfo(__func__);
[d4fa23]454 int i=0;
455 char number[MAXSTRINGSIZE];
456
457 if ((TesselStruct == NULL) || (TesselStruct->PointsOnBoundary.empty())) {
[58ed4a]458 DoeLog(1) && (eLog()<< Verbose(1) << "TesselStruct is empty." << endl);
[d4fa23]459 return false;
460 }
461
462 PointMap::iterator PointRunner;
463 while (!TesselStruct->PointsOnBoundary.empty()) {
[a67d19]464 DoLog(1) && (Log() << Verbose(1) << "Remaining points are: ");
[d4fa23]465 for (PointMap::iterator PointSprinter = TesselStruct->PointsOnBoundary.begin(); PointSprinter != TesselStruct->PointsOnBoundary.end(); PointSprinter++)
[a67d19]466 DoLog(0) && (Log() << Verbose(0) << *(PointSprinter->second) << "\t");
467 DoLog(0) && (Log() << Verbose(0) << endl);
[d4fa23]468
469 PointRunner = TesselStruct->PointsOnBoundary.begin();
470 // remove point
[e138de]471 TesselStruct->RemovePointFromTesselatedSurface(PointRunner->second);
[d4fa23]472
473 // store envelope
474 sprintf(number, "-%04d", i++);
[e138de]475 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, number);
[d4fa23]476 }
477
478 return true;
479};
480
[08ef35]481/** Creates a convex envelope from a given non-convex one.
[093645]482 * -# First step, remove concave spots, i.e. singular "dents"
483 * -# We go through all PointsOnBoundary.
484 * -# We CheckConvexityCriterion() for all its lines.
485 * -# If all its lines are concave, it cannot be on the convex envelope.
486 * -# Hence, we remove it and re-create all its triangles from its getCircleOfConnectedPoints()
487 * -# We calculate the additional volume.
488 * -# We go over all lines until none yields a concavity anymore.
489 * -# Second step, remove concave lines, i.e. line-shape "dents"
490 * -# We go through all LinesOnBoundary
491 * -# We CheckConvexityCriterion()
492 * -# If it returns concave, we flip the line in this quadrupel of points (abusing the degeneracy of the tesselation)
493 * -# We CheckConvexityCriterion(),
494 * -# if it's concave, we continue
495 * -# if not, we mark an error and stop
[08ef35]496 * Note: This routine - for free - calculates the difference in volume between convex and
497 * non-convex envelope, as the former is easy to calculate - VolumeOfConvexEnvelope() - it
498 * can be used to compute volumes of arbitrary shapes.
499 * \param *out output stream for debugging
500 * \param *TesselStruct non-convex envelope, is changed in return!
[093645]501 * \param *mol molecule
502 * \param *filename name of file
[08ef35]503 * \return volume difference between the non- and the created convex envelope
504 */
[e138de]505double ConvexizeNonconvexEnvelope(class Tesselation *&TesselStruct, const molecule * const mol, const char * const filename)
[08ef35]506{
[f67b6e]507 Info FunctionInfo(__func__);
[08ef35]508 double volume = 0;
509 class BoundaryPointSet *point = NULL;
510 class BoundaryLineSet *line = NULL;
[ad37ab]511 bool Concavity = false;
[57066a]512 char dummy[MAXSTRINGSIZE];
[ad37ab]513 PointMap::iterator PointRunner;
514 PointMap::iterator PointAdvance;
515 LineMap::iterator LineRunner;
516 LineMap::iterator LineAdvance;
517 TriangleMap::iterator TriangleRunner;
518 TriangleMap::iterator TriangleAdvance;
519 int run = 0;
[093645]520
521 // check whether there is something to work on
[08ef35]522 if (TesselStruct == NULL) {
[58ed4a]523 DoeLog(1) && (eLog()<< Verbose(1) << "TesselStruct is empty!" << endl);
[08ef35]524 return volume;
525 }
526
[093645]527 // First step: RemovePointFromTesselatedSurface
[1d9b7aa]528 do {
529 Concavity = false;
[57066a]530 sprintf(dummy, "-first-%d", run);
[e138de]531 //CalculateConcavityPerBoundaryPoint(TesselStruct);
532 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
[57066a]533
[1d9b7aa]534 PointRunner = TesselStruct->PointsOnBoundary.begin();
535 PointAdvance = PointRunner; // we need an advanced point, as the PointRunner might get removed
536 while (PointRunner != TesselStruct->PointsOnBoundary.end()) {
537 PointAdvance++;
538 point = PointRunner->second;
[a67d19]539 DoLog(1) && (Log() << Verbose(1) << "INFO: Current point is " << *point << "." << endl);
[1d9b7aa]540 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++) {
541 line = LineRunner->second;
[a67d19]542 DoLog(1) && (Log() << Verbose(1) << "INFO: Current line of point " << *point << " is " << *line << "." << endl);
[e138de]543 if (!line->CheckConvexityCriterion()) {
[57066a]544 // remove the point if needed
[a67d19]545 DoLog(1) && (Log() << Verbose(1) << "... point " << *point << " cannot be on convex envelope." << endl);
[e138de]546 volume += TesselStruct->RemovePointFromTesselatedSurface(point);
[57066a]547 sprintf(dummy, "-first-%d", ++run);
[e138de]548 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
[57066a]549 Concavity = true;
550 break;
551 }
[1d9b7aa]552 }
553 PointRunner = PointAdvance;
[093645]554 }
555
[57066a]556 sprintf(dummy, "-second-%d", run);
[e138de]557 //CalculateConcavityPerBoundaryPoint(TesselStruct);
558 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, dummy);
[093645]559
[1d9b7aa]560 // second step: PickFarthestofTwoBaselines
561 LineRunner = TesselStruct->LinesOnBoundary.begin();
562 LineAdvance = LineRunner; // we need an advanced line, as the LineRunner might get removed
563 while (LineRunner != TesselStruct->LinesOnBoundary.end()) {
564 LineAdvance++;
565 line = LineRunner->second;
[a67d19]566 DoLog(1) && (Log() << Verbose(1) << "INFO: Picking farthest baseline for line is " << *line << "." << endl);
[1d9b7aa]567 // take highest of both lines
[e138de]568 if (TesselStruct->IsConvexRectangle(line) == NULL) {
569 const double tmp = TesselStruct->PickFarthestofTwoBaselines(line);
[57066a]570 volume += tmp;
[ad37ab]571 if (tmp != 0.) {
[e138de]572 TesselStruct->FlipBaseline(line);
[57066a]573 Concavity = true;
574 }
[1d9b7aa]575 }
576 LineRunner = LineAdvance;
577 }
[57066a]578 run++;
[1d9b7aa]579 } while (Concavity);
[e138de]580 //CalculateConcavityPerBoundaryPoint(TesselStruct);
581 //StoreTrianglesinFile(mol, filename, "-third");
[093645]582
583 // third step: IsConvexRectangle
[7dea7c]584// LineRunner = TesselStruct->LinesOnBoundary.begin();
585// LineAdvance = LineRunner; // we need an advanced line, as the LineRunner might get removed
586// while (LineRunner != TesselStruct->LinesOnBoundary.end()) {
587// LineAdvance++;
588// line = LineRunner->second;
[e138de]589// Log() << Verbose(1) << "INFO: Current line is " << *line << "." << endl;
[7dea7c]590// //if (LineAdvance != TesselStruct->LinesOnBoundary.end())
[e138de]591// //Log() << Verbose(1) << "INFO: Next line will be " << *(LineAdvance->second) << "." << endl;
[7dea7c]592// if (!line->CheckConvexityCriterion(out)) {
[e138de]593// Log() << Verbose(1) << "... line " << *line << " is concave, flipping it." << endl;
[7dea7c]594//
595// // take highest of both lines
[e138de]596// point = TesselStruct->IsConvexRectangle(line);
[7dea7c]597// if (point != NULL)
[e138de]598// volume += TesselStruct->RemovePointFromTesselatedSurface(point);
[7dea7c]599// }
600// LineRunner = LineAdvance;
601// }
[093645]602
[e138de]603 CalculateConcavityPerBoundaryPoint(TesselStruct);
604 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, "");
[0077b5]605
606 // end
[a67d19]607 DoLog(0) && (Log() << Verbose(0) << "Volume is " << volume << "." << endl);
[0077b5]608 return volume;
609};
610
[6ac7ee]611
[357fba]612/** Determines the volume of a cluster.
613 * Determines first the convex envelope, then tesselates it and calculates its volume.
[6ac7ee]614 * \param *out output stream for debugging
[357fba]615 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
616 * \param *configuration needed for path to store convex envelope file
617 * \return determined volume of the cluster in cubed config:GetIsAngstroem()
[3d919e]618 */
[e138de]619double VolumeOfConvexEnvelope(class Tesselation *TesselStruct, class config *configuration)
[357fba]620{
[f67b6e]621 Info FunctionInfo(__func__);
[357fba]622 bool IsAngstroem = configuration->GetIsAngstroem();
623 double volume = 0.;
[ad37ab]624 Vector x;
625 Vector y;
[6ac7ee]626
[357fba]627 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
628 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++)
629 { // go through every triangle, calculate volume of its pyramid with CoG as peak
630 x.CopyVector(runner->second->endpoints[0]->node->node);
631 x.SubtractVector(runner->second->endpoints[1]->node->node);
632 y.CopyVector(runner->second->endpoints[0]->node->node);
633 y.SubtractVector(runner->second->endpoints[2]->node->node);
[ad37ab]634 const double a = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
635 const double b = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[2]->node->node));
636 const double c = sqrt(runner->second->endpoints[2]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
637 const double G = sqrt(((a + b + c) * (a + b + c) - 2 * (a * a + b * b + c * c)) / 16.); // area of tesselated triangle
[357fba]638 x.MakeNormalVector(runner->second->endpoints[0]->node->node, runner->second->endpoints[1]->node->node, runner->second->endpoints[2]->node->node);
[658efb]639 x.Scale(runner->second->endpoints[1]->node->node->ScalarProduct(&x));
[ad37ab]640 const double h = x.Norm(); // distance of CoG to triangle
641 const double PyramidVolume = (1. / 3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
[f67b6e]642 Log() << Verbose(1) << "Area of triangle is " << setprecision(10) << G << " "
[357fba]643 << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is "
644 << h << " and the volume is " << PyramidVolume << " "
645 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
646 volume += PyramidVolume;
[3d919e]647 }
[7f4bee]648 Log() << Verbose(0) << "RESULT: The summed volume is " << setprecision(6)
[357fba]649 << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3."
650 << endl;
[6ac7ee]651
[357fba]652 return volume;
[7dea7c]653};
654
655/** Stores triangles to file.
656 * \param *out output stream for debugging
657 * \param *mol molecule with atoms and bonds
[71b20e]658 * \param *TesselStruct Tesselation with boundary triangles
[7dea7c]659 * \param *filename prefix of filename
660 * \param *extraSuffix intermediate suffix
661 */
[71b20e]662void StoreTrianglesinFile(const molecule * const mol, const Tesselation * const TesselStruct, const char *filename, const char *extraSuffix)
[7dea7c]663{
[f67b6e]664 Info FunctionInfo(__func__);
[7dea7c]665 // 4. Store triangles in tecplot file
666 if (filename != NULL) {
667 if (DoTecplotOutput) {
668 string OutputName(filename);
669 OutputName.append(extraSuffix);
670 OutputName.append(TecplotSuffix);
671 ofstream *tecplot = new ofstream(OutputName.c_str());
[6a7f78c]672 WriteTecplotFile(tecplot, TesselStruct, mol, -1);
[7dea7c]673 tecplot->close();
674 delete(tecplot);
675 }
676 if (DoRaster3DOutput) {
677 string OutputName(filename);
678 OutputName.append(extraSuffix);
679 OutputName.append(Raster3DSuffix);
680 ofstream *rasterplot = new ofstream(OutputName.c_str());
[e138de]681 WriteRaster3dFile(rasterplot, TesselStruct, mol);
[7dea7c]682 rasterplot->close();
683 delete(rasterplot);
684 }
685 }
686};
[03648b]687
[357fba]688/** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
689 * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
690 * \param *out output stream for debugging
691 * \param *configuration needed for path to store convex envelope file
692 * \param *mol molecule structure representing the cluster
[776b64]693 * \param *&TesselStruct Tesselation structure with triangles on return
[357fba]694 * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead.
695 * \param celldensity desired average density in final cell
[8c54a3]696 */
[e138de]697void PrepareClustersinWater(config *configuration, molecule *mol, double ClusterVolume, double celldensity)
[357fba]698{
[f67b6e]699 Info FunctionInfo(__func__);
[fa649a]700 bool IsAngstroem = true;
[ad37ab]701 double *GreatestDiameter = NULL;
702 Boundaries *BoundaryPoints = NULL;
703 class Tesselation *TesselStruct = NULL;
704 Vector BoxLengths;
705 int repetition[NDIM] = { 1, 1, 1 };
706 int TotalNoClusters = 1;
707 atom *Walker = NULL;
708 double totalmass = 0.;
709 double clustervolume = 0.;
710 double cellvolume = 0.;
711
[357fba]712 // transform to PAS
[e138de]713 mol->PrincipalAxisSystem(true);
[3d919e]714
[ad37ab]715 IsAngstroem = configuration->GetIsAngstroem();
[e138de]716 GreatestDiameter = GetDiametersOfCluster(BoundaryPoints, mol, TesselStruct, IsAngstroem);
717 BoundaryPoints = GetBoundaryPoints(mol, TesselStruct);
[357fba]718 LinkedCell LCList(mol, 10.);
[e138de]719 FindConvexBorder(mol, TesselStruct, &LCList, NULL);
[ad37ab]720
721 // some preparations beforehand
[357fba]722 if (ClusterVolume == 0)
[e138de]723 clustervolume = VolumeOfConvexEnvelope(TesselStruct, configuration);
[357fba]724 else
725 clustervolume = ClusterVolume;
[ad37ab]726
[357fba]727 for (int i = 0; i < NDIM; i++)
728 TotalNoClusters *= repetition[i];
[8c54a3]729
[357fba]730 // sum up the atomic masses
[ad37ab]731 Walker = mol->start;
732 while (Walker->next != mol->end) {
[357fba]733 Walker = Walker->next;
734 totalmass += Walker->type->mass;
[ad37ab]735 }
[a67d19]736 DoLog(0) && (Log() << Verbose(0) << "RESULT: The summed mass is " << setprecision(10) << totalmass << " atomicmassunit." << endl);
737 DoLog(0) && (Log() << Verbose(0) << "RESULT: The average density is " << setprecision(10) << totalmass / clustervolume << " atomicmassunit/" << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl);
[8c54a3]738
[357fba]739 // solve cubic polynomial
[a67d19]740 DoLog(1) && (Log() << Verbose(1) << "Solving equidistant suspension in water problem ..." << endl);
[357fba]741 if (IsAngstroem)
[ad37ab]742 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_A - (totalmass / clustervolume)) / (celldensity - 1);
[357fba]743 else
[ad37ab]744 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_a0 - (totalmass / clustervolume)) / (celldensity - 1);
[a67d19]745 DoLog(1) && (Log() << Verbose(1) << "Cellvolume needed for a density of " << celldensity << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl);
[ad37ab]746
747 double minimumvolume = TotalNoClusters * (GreatestDiameter[0] * GreatestDiameter[1] * GreatestDiameter[2]);
[a67d19]748 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]749 if (minimumvolume > cellvolume) {
[58ed4a]750 DoeLog(1) && (eLog()<< Verbose(1) << "the containing box already has a greater volume than the envisaged cell volume!" << endl);
[a67d19]751 DoLog(0) && (Log() << Verbose(0) << "Setting Box dimensions to minimum possible, the greatest diameters." << endl);
[ad37ab]752 for (int i = 0; i < NDIM; i++)
753 BoxLengths.x[i] = GreatestDiameter[i];
[e138de]754 mol->CenterEdge(&BoxLengths);
[ad37ab]755 } else {
756 BoxLengths.x[0] = (repetition[0] * GreatestDiameter[0] + repetition[1] * GreatestDiameter[1] + repetition[2] * GreatestDiameter[2]);
757 BoxLengths.x[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]);
758 BoxLengths.x[2] = minimumvolume - cellvolume;
759 double x0 = 0.;
760 double x1 = 0.;
761 double x2 = 0.;
762 if (gsl_poly_solve_cubic(BoxLengths.x[0], BoxLengths.x[1], BoxLengths.x[2], &x0, &x1, &x2) == 1) // either 1 or 3 on return
[a67d19]763 DoLog(0) && (Log() << Verbose(0) << "RESULT: The resulting spacing is: " << x0 << " ." << endl);
[ad37ab]764 else {
[a67d19]765 DoLog(0) && (Log() << Verbose(0) << "RESULT: The resulting spacings are: " << x0 << " and " << x1 << " and " << x2 << " ." << endl);
[ad37ab]766 x0 = x2; // sorted in ascending order
[357fba]767 }
[8c54a3]768
[ad37ab]769 cellvolume = 1.;
770 for (int i = 0; i < NDIM; i++) {
771 BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]);
772 cellvolume *= BoxLengths.x[i];
[8c54a3]773 }
[ad37ab]774
775 // set new box dimensions
[a67d19]776 DoLog(0) && (Log() << Verbose(0) << "Translating to box with these boundaries." << endl);
[ad37ab]777 mol->SetBoxDimension(&BoxLengths);
[e138de]778 mol->CenterInBox();
[ad37ab]779 }
[357fba]780 // update Box of atoms by boundary
781 mol->SetBoxDimension(&BoxLengths);
[a67d19]782 DoLog(0) && (Log() << Verbose(0) << "RESULT: The resulting cell dimensions are: " << BoxLengths.x[0] << " and " << BoxLengths.x[1] << " and " << BoxLengths.x[2] << " with total volume of " << cellvolume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl);
[ad37ab]783};
[8c54a3]784
785
[357fba]786/** Fills the empty space of the simulation box with water/
787 * \param *out output stream for debugging
788 * \param *List list of molecules already present in box
789 * \param *TesselStruct contains tesselated surface
790 * \param *filler molecule which the box is to be filled with
791 * \param configuration contains box dimensions
[775d133]792 * \param MaxDistance fills in molecules only up to this distance (set to -1 if whole of the domain)
[357fba]793 * \param distance[NDIM] distance between filling molecules in each direction
[9473f6]794 * \param boundary length of boundary zone between molecule and filling mollecules
[71b20e]795 * \param epsilon distance to surface which is not filled
[357fba]796 * \param RandAtomDisplacement maximum distance for random displacement per atom
797 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
798 * \param DoRandomRotation true - do random rotiations, false - don't
799 * \return *mol pointer to new molecule with filled atoms
[6ac7ee]800 */
[775d133]801molecule * 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]802{
[f67b6e]803 Info FunctionInfo(__func__);
[357fba]804 molecule *Filling = new molecule(filler->elemente);
805 Vector CurrentPosition;
806 int N[NDIM];
807 int n[NDIM];
[b34306]808 double *M = ReturnFullMatrixforSymmetric(World::get()->cell_size);
[357fba]809 double Rotations[NDIM*NDIM];
[30d9e7]810 double *MInverse = InverseMatrix(M);
[357fba]811 Vector AtomTranslations;
812 Vector FillerTranslations;
813 Vector FillerDistance;
[30d9e7]814 Vector Inserter;
[357fba]815 double FillIt = false;
[ef0e6d]816 atom *Walker = NULL;
[357fba]817 bond *Binder = NULL;
[ad37ab]818 double phi[NDIM];
[30d9e7]819 map<molecule *, Tesselation *> TesselStruct;
820 map<molecule *, LinkedCell *> LCList;
[ef0e6d]821
[c5805a]822 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++)
823 if ((*ListRunner)->AtomCount > 0) {
[a67d19]824 DoLog(1) && (Log() << Verbose(1) << "Pre-creating linked cell lists for molecule " << *ListRunner << "." << endl);
[c5805a]825 LCList[(*ListRunner)] = new LinkedCell((*ListRunner), 10.); // get linked cell list
[a67d19]826 DoLog(1) && (Log() << Verbose(1) << "Pre-creating tesselation for molecule " << *ListRunner << "." << endl);
[c5805a]827 TesselStruct[(*ListRunner)] = NULL;
828 FindNonConvexBorder((*ListRunner), TesselStruct[(*ListRunner)], (const LinkedCell *&)LCList[(*ListRunner)], 5., NULL);
829 }
[8c54a3]830
[357fba]831 // Center filler at origin
[c5805a]832 filler->CenterEdge(&Inserter);
[357fba]833 filler->Center.Zero();
[a67d19]834 DoLog(2) && (Log() << Verbose(2) << "INFO: Filler molecule has the following bonds:" << endl);
[a837d0]835 Binder = filler->first;
836 while(Binder->next != filler->last) {
837 Binder = Binder->next;
[a67d19]838 DoLog(2) && (Log() << Verbose(2) << " " << *Binder << endl);
[a837d0]839 }
[8c54a3]840
[e138de]841 filler->CountAtoms();
[ef0e6d]842 atom * CopyAtoms[filler->AtomCount];
843
[357fba]844 // calculate filler grid in [0,1]^3
845 FillerDistance.Init(distance[0], distance[1], distance[2]);
846 FillerDistance.InverseMatrixMultiplication(M);
[71b20e]847 for(int i=0;i<NDIM;i++)
[ab1932]848 N[i] = (int) ceil(1./FillerDistance.x[i]);
[a67d19]849 DoLog(1) && (Log() << Verbose(1) << "INFO: Grid steps are " << N[0] << ", " << N[1] << ", " << N[2] << "." << endl);
[8c54a3]850
[d6eb80]851 // initialize seed of random number generator to current time
852 srand ( time(NULL) );
853
[357fba]854 // go over [0,1]^3 filler grid
[c5805a]855 for (n[0] = 0; n[0] < N[0]; n[0]++)
856 for (n[1] = 0; n[1] < N[1]; n[1]++)
857 for (n[2] = 0; n[2] < N[2]; n[2]++) {
[357fba]858 // calculate position of current grid vector in untransformed box
[ef0e6d]859 CurrentPosition.Init((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
[357fba]860 CurrentPosition.MatrixMultiplication(M);
[30d9e7]861 // create molecule random translation vector ...
862 for (int i=0;i<NDIM;i++)
863 FillerTranslations.x[i] = RandomMolDisplacement*(rand()/(RAND_MAX/2.) - 1.);
[a67d19]864 DoLog(2) && (Log() << Verbose(2) << "INFO: Current Position is " << CurrentPosition << "+" << FillerTranslations << "." << endl);
[8c54a3]865
[30d9e7]866 // go through all atoms
[c5805a]867 for (int i=0;i<filler->AtomCount;i++)
868 CopyAtoms[i] = NULL;
[30d9e7]869 Walker = filler->start;
870 while (Walker->next != filler->end) {
871 Walker = Walker->next;
[8c54a3]872
[30d9e7]873 // create atomic random translation vector ...
[357fba]874 for (int i=0;i<NDIM;i++)
[30d9e7]875 AtomTranslations.x[i] = RandomAtomDisplacement*(rand()/(RAND_MAX/2.) - 1.);
[8c54a3]876
[30d9e7]877 // ... and rotation matrix
878 if (DoRandomRotation) {
879 for (int i=0;i<NDIM;i++) {
880 phi[i] = rand()/(RAND_MAX/(2.*M_PI));
[8c54a3]881 }
882
[30d9e7]883 Rotations[0] = cos(phi[0]) *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2]));
884 Rotations[3] = sin(phi[0]) *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2]));
885 Rotations[6] = cos(phi[1])*sin(phi[2]) ;
886 Rotations[1] = - sin(phi[0])*cos(phi[1]) ;
887 Rotations[4] = cos(phi[0])*cos(phi[1]) ;
888 Rotations[7] = sin(phi[1]) ;
889 Rotations[3] = - cos(phi[0]) *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2]));
890 Rotations[5] = - sin(phi[0]) *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2]));
891 Rotations[8] = cos(phi[1])*cos(phi[2]) ;
892 }
[f3278b]893
[30d9e7]894 // ... and put at new position
895 Inserter.CopyVector(&(Walker->x));
896 if (DoRandomRotation)
897 Inserter.MatrixMultiplication(Rotations);
898 Inserter.AddVector(&AtomTranslations);
899 Inserter.AddVector(&FillerTranslations);
900 Inserter.AddVector(&CurrentPosition);
901
902 // check whether inserter is inside box
903 Inserter.MatrixMultiplication(MInverse);
904 FillIt = true;
905 for (int i=0;i<NDIM;i++)
906 FillIt = FillIt && (Inserter.x[i] >= -MYEPSILON) && ((Inserter.x[i]-1.) <= MYEPSILON);
907 Inserter.MatrixMultiplication(M);
908
909 // Check whether point is in- or outside
910 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
911 // get linked cell list
[c5805a]912 if (TesselStruct[(*ListRunner)] != NULL) {
[8db598]913 const double distance = (TesselStruct[(*ListRunner)]->GetDistanceToSurface(Inserter, LCList[(*ListRunner)]));
914 FillIt = FillIt && (distance > boundary) && ((MaxDistance < 0) || (MaxDistance > distance));
[30d9e7]915 }
916 }
917 // insert into Filling
918 if (FillIt) {
[a67d19]919 DoLog(1) && (Log() << Verbose(1) << "INFO: Position at " << Inserter << " is outer point." << endl);
[30d9e7]920 // copy atom ...
921 CopyAtoms[Walker->nr] = new atom(Walker);
922 CopyAtoms[Walker->nr]->x.CopyVector(&Inserter);
[ef0e6d]923 Filling->AddAtom(CopyAtoms[Walker->nr]);
[a67d19]924 DoLog(4) && (Log() << Verbose(4) << "Filling atom " << *Walker << ", translated to " << AtomTranslations << ", at final position is " << (CopyAtoms[Walker->nr]->x) << "." << endl);
[30d9e7]925 } else {
[a67d19]926 DoLog(1) && (Log() << Verbose(1) << "INFO: Position at " << Inserter << " is inner point, within boundary or outside of MaxDistance." << endl);
[30d9e7]927 CopyAtoms[Walker->nr] = NULL;
[c5805a]928 continue;
[357fba]929 }
[a837d0]930 }
931 // go through all bonds and add as well
932 Binder = filler->first;
933 while(Binder->next != filler->last) {
934 Binder = Binder->next;
935 if ((CopyAtoms[Binder->leftatom->nr] != NULL) && (CopyAtoms[Binder->rightatom->nr] != NULL)) {
936 Log() << Verbose(3) << "Adding Bond between " << *CopyAtoms[Binder->leftatom->nr] << " and " << *CopyAtoms[Binder->rightatom->nr]<< "." << endl;
937 Filling->AddBond(CopyAtoms[Binder->leftatom->nr], CopyAtoms[Binder->rightatom->nr], Binder->BondDegree);
[8c54a3]938 }
939 }
940 }
[1614174]941 Free(&M);
[30d9e7]942 Free(&MInverse);
[71b20e]943
[357fba]944 return Filling;
[3d919e]945};
[8c54a3]946
947
[6ac7ee]948/** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
949 * \param *out output stream for debugging
950 * \param *mol molecule structure with Atom's and Bond's
[776b64]951 * \param *&TesselStruct Tesselation filled with points, lines and triangles on boundary on return
952 * \param *&LCList atoms in LinkedCell list
[57066a]953 * \param RADIUS radius of the virtual sphere
[6ac7ee]954 * \param *filename filename prefix for output of vertex data
[4fc93f]955 * \return true - tesselation successful, false - tesselation failed
[6ac7ee]956 */
[4fc93f]957bool FindNonConvexBorder(const molecule* const mol, Tesselation *&TesselStruct, const LinkedCell *&LCList, const double RADIUS, const char *filename = NULL)
[03648b]958{
[f67b6e]959 Info FunctionInfo(__func__);
[3d919e]960 bool freeLC = false;
[4fc93f]961 bool status = false;
[6613ec]962 CandidateForTesselation *baseline = NULL;
[1e168b]963 bool OneLoopWithoutSuccessFlag = true; // marks whether we went once through all baselines without finding any without two triangles
[ad37ab]964 bool TesselationFailFlag = false;
[357fba]965
[776b64]966 if (TesselStruct == NULL) {
[a67d19]967 DoLog(1) && (Log() << Verbose(1) << "Allocating Tesselation struct ..." << endl);
[776b64]968 TesselStruct= new Tesselation;
[ef0e6d]969 } else {
[776b64]970 delete(TesselStruct);
[a67d19]971 DoLog(1) && (Log() << Verbose(1) << "Re-Allocating Tesselation struct ..." << endl);
[776b64]972 TesselStruct = new Tesselation;
[3d919e]973 }
[ad37ab]974
[57066a]975 // initialise Linked Cell
[3d919e]976 if (LCList == NULL) {
977 LCList = new LinkedCell(mol, 2.*RADIUS);
978 freeLC = true;
979 }
980
[57066a]981 // 1. get starting triangle
[ce70970]982 if (!TesselStruct->FindStartingTriangle(RADIUS, LCList)) {
983 DoeLog(0) && (eLog() << Verbose(0) << "No valid starting triangle found." << endl);
[b5c2d7]984 //performCriticalExit();
[ce70970]985 }
[f8bd7d]986 if (filename != NULL) {
987 if ((DoSingleStepOutput && ((TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
988 TesselStruct->Output(filename, mol);
989 }
990 }
[3d919e]991
[57066a]992 // 2. expand from there
[1e168b]993 while ((!TesselStruct->OpenLines.empty()) && (OneLoopWithoutSuccessFlag)) {
[b40a93]994 (cerr << "There are " << TesselStruct->TrianglesOnBoundary.size() << " triangles and " << TesselStruct->OpenLines.size() << " open lines to scan for candidates." << endl);
995 // 2a. print OpenLines without candidates
996 DoLog(1) && (Log() << Verbose(1) << "There are the following open lines to scan for a candidates:" << endl);
[1e168b]997 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
[b40a93]998 if (Runner->second->pointlist.empty())
999 DoLog(1) && (Log() << Verbose(1) << " " << *(Runner->second) << endl);
[1e168b]1000
[734816]1001 // 2b. find best candidate for each OpenLine
[6613ec]1002 TesselationFailFlag = TesselStruct->FindCandidatesforOpenLines(RADIUS, LCList);
[3d919e]1003
[734816]1004 // 2c. print OpenLines with candidates again
[a67d19]1005 DoLog(1) && (Log() << Verbose(1) << "There are " << TesselStruct->OpenLines.size() << " open lines to scan for the best candidates:" << endl);
[1e168b]1006 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++)
[a67d19]1007 DoLog(1) && (Log() << Verbose(1) << " " << *(Runner->second) << endl);
[1e168b]1008
[734816]1009 // 2d. search for smallest ShortestAngle among all candidates
1010 double ShortestAngle = 4.*M_PI;
[1e168b]1011 for (CandidateMap::iterator Runner = TesselStruct->OpenLines.begin(); Runner != TesselStruct->OpenLines.end(); Runner++) {
[474961]1012 if (Runner->second->ShortestAngle < ShortestAngle) {
1013 baseline = Runner->second;
1014 ShortestAngle = baseline->ShortestAngle;
[a67d19]1015 DoLog(1) && (Log() << Verbose(1) << "New best candidate is " << *baseline->BaseLine << " with point " << *(*baseline->pointlist.begin()) << " and angle " << baseline->ShortestAngle << endl);
[1e168b]1016 }
1017 }
[734816]1018 // 2e. if we found one, add candidate
[f67b6e]1019 if ((ShortestAngle == 4.*M_PI) || (baseline->pointlist.empty()))
[7dea7c]1020 OneLoopWithoutSuccessFlag = false;
[1e168b]1021 else {
[474961]1022 TesselStruct->AddCandidatePolygon(*baseline, RADIUS, LCList);
[1e168b]1023 }
1024
[734816]1025 // 2f. write temporary envelope
[1e168b]1026 if (filename != NULL) {
1027 if ((DoSingleStepOutput && ((TesselStruct->TrianglesOnBoundary.size() % SingleStepWidth == 0)))) { // if we have a new triangle and want to output each new triangle configuration
1028 TesselStruct->Output(filename, mol);
1029 }
[3d919e]1030 }
1031 }
[4fc93f]1032// // check envelope for consistency
1033// status = CheckListOfBaselines(TesselStruct);
1034//
1035// // look whether all points are inside of the convex envelope, otherwise add them via degenerated triangles
1036// //->InsertStraddlingPoints(mol, LCList);
[57066a]1037// mol->GoToFirst();
1038// class TesselPoint *Runner = NULL;
1039// while (!mol->IsEnd()) {
1040// Runner = mol->GetPoint();
[e138de]1041// Log() << Verbose(1) << "Checking on " << Runner->Name << " ... " << endl;
1042// if (!->IsInnerPoint(Runner, LCList)) {
1043// Log() << Verbose(2) << Runner->Name << " is outside of envelope, adding via degenerated triangles." << endl;
1044// ->AddBoundaryPointByDegeneratedTriangle(Runner, LCList);
[57066a]1045// } else {
[e138de]1046// Log() << Verbose(2) << Runner->Name << " is inside of or on envelope." << endl;
[57066a]1047// }
1048// mol->GoToNext();
1049// }
[357fba]1050
[f67b6e]1051// // Purges surplus triangles.
1052// TesselStruct->RemoveDegeneratedTriangles();
[4fc93f]1053
[b998c3]1054 // check envelope for consistency
1055 status = CheckListOfBaselines(TesselStruct);
1056
1057 // store before correction
1058 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, "");
1059
[6613ec]1060// // correct degenerated polygons
1061// TesselStruct->CorrectAllDegeneratedPolygons();
1062//
1063// // check envelope for consistency
1064// status = CheckListOfBaselines(TesselStruct);
[ef0e6d]1065
[57066a]1066 // write final envelope
[e138de]1067 CalculateConcavityPerBoundaryPoint(TesselStruct);
1068 StoreTrianglesinFile(mol, (const Tesselation *&)TesselStruct, filename, "");
[8c54a3]1069
[3d919e]1070 if (freeLC)
1071 delete(LCList);
[4fc93f]1072
1073 return status;
[6ac7ee]1074};
[03648b]1075
[57066a]1076
[ad37ab]1077/** Finds a hole of sufficient size in \a *mols to embed \a *srcmol into it.
[ca2587]1078 * \param *out output stream for debugging
[ad37ab]1079 * \param *mols molecules in the domain to embed in between
1080 * \param *srcmol embedding molecule
[ca2587]1081 * \return *Vector new center of \a *srcmol for embedding relative to \a this
1082 */
[e138de]1083Vector* FindEmbeddingHole(MoleculeListClass *mols, molecule *srcmol)
[ca2587]1084{
[f67b6e]1085 Info FunctionInfo(__func__);
[ca2587]1086 Vector *Center = new Vector;
1087 Center->Zero();
1088 // calculate volume/shape of \a *srcmol
1089
1090 // find embedding holes
1091
1092 // if more than one, let user choose
1093
1094 // return embedding center
1095 return Center;
1096};
1097
Note: See TracBrowser for help on using the repository browser.