source: src/boundary.cpp@ ad37ab

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 Candidate_v1.7.0 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 ad37ab was ad37ab, checked in by Frederik Heber <heber@…>, 16 years ago

analyzer.cpp and boundary.cpp refactored.

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