source: src/boundary.cpp@ 12cf773

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

Made the world store the cell_size within a Box object.

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