source: src/boundary.cpp@ 0286bc

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

Fix of PrepareClustersInWater (at least it does not stumble over memory issues).

  • note: this was just done to make check test Filling/2 work again (which only runs and does not check the output)
  • GetBoundaryPoints() - using now left and right to have a good runner even if it is discarded/deleted, flag check when loop is through
  • PrepareClustersinWater() - LCList is now a pointer and removed after FindConvexBorder()
  • DOCUFIX: Tesselation::RemoveTesselationTriangle() - triangles attached to lines are printed starting on next line, not current
  • BUGFIX: Tesselation::FlipBaseline() - as we remove the two connected triangles, the baseline who they are attached to will be deleted and removed, hence the loop over the line's triangles does not work. Now, we first put all into a list, then delete the triangles.

This was the last test to fail. All unit tests (33), all testsuite cases (45) and all tesselation tests (15) work.

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

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