source: src/boundary.cpp@ 36166d

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 36166d was 36166d, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Removed left over parts from old memory-tracker

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