source: src/boundary.cpp@ 61ea5b

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 61ea5b was 4e10f5, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Merge branch 'stable' into StructureRefactoring

Conflicts:

src/Actions/WorldAction/CenterOnEdgeAction.cpp
src/Actions/WorldAction/ChangeBoxAction.cpp
src/Actions/WorldAction/RepeatBoxAction.cpp
src/Actions/WorldAction/ScaleBoxAction.cpp
src/World.cpp
src/boundary.cpp

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