source: src/boundary.cpp@ b11d3b

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

Filling has a MaxDistance, somes changes to the Correlation Analysis.

Correlation:

  • OutputCorrelation() have setprecision(8), as irregularities appeared in the output files with regard to the number of digits.
  • ParseCommandLineOptions() for case 'C' now needs BinStart and BinEnd. However, may be set to 0,0 (search for yourself), or (0,-1) (start at 0, but search end for yourself).
  • BUGFIX: argument index of element parameter was wrong from the change [E/P/S].

Filling:

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