source: src/boundary.cpp@ 6ef0a4

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 6ef0a4 was d51975, checked in by Frederik Heber <heber@…>, 15 years ago

Small changes to FindConvexBorder().

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

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