source: src/boundary.cpp@ 190326

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

Simplified tesselation.cpp by allowing direct access to derived triangle internals

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