source: src/boundary.cpp@ 91e7e4a

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 91e7e4a was d4fa23, checked in by Frederik Heber <heber@…>, 16 years ago

New function RemoveAllBoundaryPoints() for sequentially removing all boundary points.

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