source: src/boundary.cpp@ 791138

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 791138 was 6a7f78c, checked in by Frederik Heber <heber@…>, 16 years ago

Fixes and naming of final Tecplot output file is now molecule name.

  • FIXES to builder.cpp:
    • case 'p' would not dissect the molecule into connected subgraphs
    • if done so, the BondGraph was not yet initialised
    • if done so, we need to check whether BondGraphFileName has been set
    • BondGraphFileName.empty() could not be used as a check, as was set to "" instead of "\n"
    • if (finally) done so, we have to remove the empty molecule that we parsed in
    • ... and then pick the newly added molecule for mol to point at
    • SaveConfig() did not set the merged molecule name correctly.
    • if empty config is given, the empty molecule now receives the ConfigFileName as name
  • FIXES to config.cpp
    • Load() did not set the name of the molecule
  • changes to tesselationhelper.cpp and tesselation.cpp
  • changes to PointCloud and molecule
    • new virtual function PointCloud::GetName() returns "unknown"
    • new function molecule::GetName() returns pointer to name of molecule
    • IsEmpty() and IsEnd() now return true by default
  • all .dat files in the "Tesselations" tests were changed accordingly (i.e. have now the name in the second line)
  • benzene was added as a new test for an absolutely flat molecule. So far, it fails horribly.
  • 13 of 17 tests run fine

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

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