source: src/boundary.cpp@ c0917c

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 c0917c was 29812d, checked in by Saskia Metzler <metzler@…>, 16 years ago

Ticket 11: use templates and/or traits to fix Malloc/ReAlloc-Free warnings in a clean manner

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