source: src/boundary.cpp@ e41951

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 e41951 was fcd7b6, checked in by Frederik Heber <heber@…>, 15 years ago

In molecule::OutputTrajectories() ActOnAllAtoms() with new function atom::OutputTrajectory() is used.

For this to work, I had to change the Trajectory struct that was so far included in molecule.hpp to be incorporated directly into the class atom.
NOTE: This incorporation is incomplete and a ticket (#34) has been filed to remind of this issue.
However, the trajectory is better suited to reside in atom anyway and was probably just put in molecule due to memory prejudices against STL vector<>.
Functions in molecule.cpp, config.cpp, molecule_geometry.cpp and molecule_dynamics.cpp were adapted (changed from Trajectories[atom *] to atom *->Trajectory).
And the atom pointer in the Trajectory structure was removed.

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