source: src/boundary.cpp@ a7b761b

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since a7b761b was a7b761b, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Merge branch 'MoleculeStartEndSwitch' into StructureRefactoring

Conflicts:

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

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