source: src/boundary.cpp@ a7b761b

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

Merge branch 'MoleculeStartEndSwitch' into StructureRefactoring

Conflicts:

molecuilder/src/Helpers/Assert.cpp
molecuilder/src/Helpers/Assert.hpp
molecuilder/src/Legacy/oldmenu.cpp
molecuilder/src/Makefile.am
molecuilder/src/Patterns/Cacheable.hpp
molecuilder/src/Patterns/Observer.cpp
molecuilder/src/Patterns/Observer.hpp
molecuilder/src/analysis_correlation.cpp
molecuilder/src/boundary.cpp
molecuilder/src/builder.cpp
molecuilder/src/config.cpp
molecuilder/src/helpers.hpp
molecuilder/src/molecule.cpp
molecuilder/src/molecule.hpp
molecuilder/src/molecule_dynamics.cpp
molecuilder/src/molecule_fragmentation.cpp
molecuilder/src/molecule_geometry.cpp
molecuilder/src/molecule_graph.cpp
molecuilder/src/moleculelist.cpp
molecuilder/src/tesselation.cpp
molecuilder/src/unittests/AnalysisCorrelationToSurfaceUnitTest.cpp
molecuilder/src/unittests/ObserverTest.cpp
molecuilder/src/unittests/ObserverTest.hpp

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