source: src/boundary.cpp@ 481601

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 481601 was 9473f6, checked in by Frederik Heber <heber@…>, 15 years ago

FillBoxWithMolecule now allows boundary between filler molecules and the surface.

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