source: src/boundary.cpp@ 5f612ee

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 Candidate_v1.7.0 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 5f612ee was 5f612ee, checked in by Frederik Heber <heber@…>, 16 years ago

Merge branch 'Analysis_PairCorrelation' into StructureRefactoring

Conflicts:

molecuilder/src/Makefile.am
molecuilder/src/World.cpp
molecuilder/src/World.hpp
molecuilder/src/boundary.cpp
molecuilder/src/builder.cpp
molecuilder/src/log.cpp
molecuilder/src/moleculelist.cpp
molecuilder/src/periodentafel.cpp
molecuilder/src/tesselation.cpp
molecuilder/src/unittests/AnalysisCorrelationToSurfaceUnitTest.cpp
molecuilder/src/unittests/Makefile.am
molecuilder/src/unittests/bondgraphunittest.cpp
molecuilder/src/unittests/gslvectorunittest.cpp
molecuilder/src/unittests/logunittest.cpp
molecuilder/src/unittests/tesselation_boundarytriangleunittest.hpp
molecuilder/src/vector.cpp
molecuilder/tests/Tesselations/defs.in

Conflicts have been many and too numerous to listen here, just the few general cases

  • new molecule() replaced by World::getInstance().createMolecule()
  • new atom() replaced by World::getInstance().createAtom() where appropriate.
  • Some DoLog()s added interfered with changes to the message produced by Log() << Verbose(.) << ...
  • DoLog() has been erroneously added to TestRunner.cpp as well, there cout is appropriate
  • ...

Additionally, there was a bug in atom::clone(), sort was set to atom::nr of the atom to clone not of the clone itself. This caused a failure of the fragmentation.

This merge has been fully checked from a clean build directory with subsequent configure,make all install and make check.
It configures, compiles and runs all test cases and the test suite without errors.

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