source: src/boundary.cpp@ 44de80

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 44de80 was 8f4df1, checked in by Frederik Heber <heber@…>, 15 years ago

Merge branch 'AtomicPositionEncapsulation' into stable

Conflicts:

src/Actions/AtomAction/ChangeElementAction.cpp
src/Actions/WorldAction/RemoveSphereOfAtomsAction.cpp
src/Makefile.am
src/UIElements/TextUI/TextDialog.cpp
src/analysis_correlation.hpp
src/atom.cpp
src/atom_atominfo.hpp
src/bond.cpp
src/boundary.cpp
src/molecule_geometry.cpp
src/tesselation.cpp
src/tesselationhelpers.cpp
src/triangleintersectionlist.cpp
src/unittests/Makefile.am

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