source: src/boundary.cpp@ 0077b5

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

Further bugfixes to three-step-procedure in convex envelope, not yet working.

  • Property mode set to 100755
File size: 58.2 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 write_vrml_file(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 write_raster3d_file(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 write_tecplot_file(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.Projection(&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 Find_convex_border(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 find_convex_border" << 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 write_tecplot_file(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 write_raster3d_file(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 write_tecplot_file(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 write_raster3d_file(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 find_convex_border" << endl;
578};
579
580/** Creates a convex envelope from a given non-convex one.
581 * -# First step, remove concave spots, i.e. singular "dents"
582 * -# We go through all PointsOnBoundary.
583 * -# We CheckConvexityCriterion() for all its lines.
584 * -# If all its lines are concave, it cannot be on the convex envelope.
585 * -# Hence, we remove it and re-create all its triangles from its getCircleOfConnectedPoints()
586 * -# We calculate the additional volume.
587 * -# We go over all lines until none yields a concavity anymore.
588 * -# Second step, remove concave lines, i.e. line-shape "dents"
589 * -# We go through all LinesOnBoundary
590 * -# We CheckConvexityCriterion()
591 * -# If it returns concave, we flip the line in this quadrupel of points (abusing the degeneracy of the tesselation)
592 * -# We CheckConvexityCriterion(),
593 * -# if it's concave, we continue
594 * -# if not, we mark an error and stop
595 * Note: This routine - for free - calculates the difference in volume between convex and
596 * non-convex envelope, as the former is easy to calculate - VolumeOfConvexEnvelope() - it
597 * can be used to compute volumes of arbitrary shapes.
598 * \param *out output stream for debugging
599 * \param *TesselStruct non-convex envelope, is changed in return!
600 * \param *mol molecule
601 * \param *filename name of file
602 * \return volume difference between the non- and the created convex envelope
603 */
604double ConvexizeNonconvexEnvelope(ofstream *out, class Tesselation *TesselStruct, molecule *mol, char *filename)
605{
606 double volume = 0;
607 class BoundaryPointSet *point = NULL;
608 class BoundaryLineSet *line = NULL;
609 bool Concavity;
610 PointMap::iterator PointRunner, PointAdvance;
611 LineMap::iterator LineRunner, LineAdvance;
612 TriangleMap::iterator TriangleRunner, TriangleAdvance;
613
614 *out << Verbose(0) << "Begin of ConvexizeNonconvexEnvelope" << endl;
615
616 // check whether there is something to work on
617 if (TesselStruct == NULL) {
618 *out << Verbose(1) << "ERROR: TesselStruct is empty!" << endl;
619 return volume;
620 }
621
622 //CalculateConcavityPerBoundaryPoint(out, TesselStruct);
623 StoreTrianglesinFile(out, mol, filename, "-first");
624
625 // First step: RemovePointFromTesselatedSurface
626 PointRunner = TesselStruct->PointsOnBoundary.begin();
627 PointAdvance = PointRunner; // we need an advanced point, as the PointRunner might get removed
628 while (PointRunner != TesselStruct->PointsOnBoundary.end()) {
629 PointAdvance++;
630 point = PointRunner->second;
631 *out << Verbose(1) << "INFO: Current point is " << *point << "." << endl;
632 Concavity = true;
633 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++) {
634 line = LineRunner->second;
635 *out << Verbose(2) << "INFO: Current line of point " << *point << " is " << *line << "." << endl;
636 Concavity = Concavity && (!line->CheckConvexityCriterion(out));
637 }
638 if (Concavity) {
639 *out << Verbose(1) << "... point " << *point << " cannot be on convex envelope." << endl;
640 // remove the point
641 TesselStruct->RemovePointFromTesselatedSurface(out, point);
642 }
643 PointRunner = PointAdvance;
644 }
645
646 //CalculateConcavityPerBoundaryPoint(out, TesselStruct);
647 StoreTrianglesinFile(out, mol, filename, "-second");
648
649 // second step: PickFarthestofTwoBaselines
650 LineRunner = TesselStruct->LinesOnBoundary.begin();
651 LineAdvance = LineRunner; // we need an advanced line, as the LineRunner might get removed
652 while (LineRunner != TesselStruct->LinesOnBoundary.end()) {
653 LineAdvance++;
654 line = LineRunner->second;
655 *out << Verbose(1) << "INFO: Picking farthest baseline for line is " << *line << "." << endl;
656 // take highest of both lines
657 if (TesselStruct->IsConvexRectangle(out, line) == NULL)
658 TesselStruct->PickFarthestofTwoBaselines(out, line);
659 LineRunner = LineAdvance;
660 }
661
662 //CalculateConcavityPerBoundaryPoint(out, TesselStruct);
663 StoreTrianglesinFile(out, mol, filename, "-third");
664
665 // third step: IsConvexRectangle
666 LineRunner = TesselStruct->LinesOnBoundary.begin();
667 LineAdvance = LineRunner; // we need an advanced line, as the LineRunner might get removed
668 while (LineRunner != TesselStruct->LinesOnBoundary.end()) {
669 LineAdvance++;
670 line = LineRunner->second;
671 *out << Verbose(1) << "INFO: Current line is " << *line << "." << endl;
672 if (LineAdvance != TesselStruct->LinesOnBoundary.end())
673 *out << Verbose(1) << "INFO: Next line will be " << *(LineAdvance->second) << "." << endl;
674 if (!line->CheckConvexityCriterion(out)) {
675 *out << Verbose(1) << "... line " << *line << " is concave, flipping it." << endl;
676
677 // take highest of both lines
678 point = TesselStruct->IsConvexRectangle(out, line);
679 if (point != NULL)
680 TesselStruct->RemovePointFromTesselatedSurface(out, point);
681 }
682 LineRunner = LineAdvance;
683 }
684
685 CalculateConcavityPerBoundaryPoint(out, TesselStruct);
686
687 // end
688 *out << Verbose(0) << "End of ConvexizeNonconvexEnvelope" << endl;
689 return volume;
690};
691
692/** Calculates the concavity for each of the BoundaryPointSet's in a Tesselation.
693 * Sets BoundaryPointSet::value equal to the number of connected lines that are not convex.
694 * \param *out output stream for debugging
695 * \param *TesselStruct pointer to Tesselation structure
696 */
697void CalculateConcavityPerBoundaryPoint(ofstream *out, class Tesselation *TesselStruct)
698{
699 class BoundaryPointSet *point = NULL;
700 class BoundaryLineSet *line = NULL;
701 // calculate remaining concavity
702 for (PointMap::iterator PointRunner = TesselStruct->PointsOnBoundary.begin(); PointRunner != TesselStruct->PointsOnBoundary.end(); PointRunner++) {
703 point = PointRunner->second;
704 *out << Verbose(1) << "INFO: Current point is " << *point << "." << endl;
705 point->value = 0;
706 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++) {
707 line = LineRunner->second;
708 *out << Verbose(2) << "INFO: Current line of point " << *point << " is " << *line << "." << endl;
709 if (!line->CheckConvexityCriterion(out))
710 point->value += 1;
711 }
712 }
713};
714
715/** Stores triangles to file.
716 * \param *out output stream for debugging
717 * \param *mol molecule with atoms and bonds
718 * \param *filename prefix of filename
719 * \param *extraSuffix intermediate suffix
720 */
721void StoreTrianglesinFile(ofstream *out, molecule *mol, const char *filename, const char *extraSuffix)
722{
723 // 4. Store triangles in tecplot file
724 if (filename != NULL) {
725 if (DoTecplotOutput) {
726 string OutputName(filename);
727 OutputName.append(extraSuffix);
728 OutputName.append(TecplotSuffix);
729 ofstream *tecplot = new ofstream(OutputName.c_str());
730 write_tecplot_file(out, tecplot, mol->TesselStruct, mol, 0);
731 tecplot->close();
732 delete(tecplot);
733 }
734 if (DoRaster3DOutput) {
735 string OutputName(filename);
736 OutputName.append(extraSuffix);
737 OutputName.append(Raster3DSuffix);
738 ofstream *rasterplot = new ofstream(OutputName.c_str());
739 write_raster3d_file(out, rasterplot, mol->TesselStruct, mol);
740 rasterplot->close();
741 delete(rasterplot);
742 }
743 }
744};
745
746/** Determines the volume of a cluster.
747 * Determines first the convex envelope, then tesselates it and calculates its volume.
748 * \param *out output stream for debugging
749 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
750 * \param *configuration needed for path to store convex envelope file
751 * \return determined volume of the cluster in cubed config:GetIsAngstroem()
752 */
753double VolumeOfConvexEnvelope(ofstream *out, class Tesselation *TesselStruct, class config *configuration)
754{
755 bool IsAngstroem = configuration->GetIsAngstroem();
756 double volume = 0.;
757 double PyramidVolume = 0.;
758 double G, h;
759 Vector x, y;
760 double a, b, c;
761
762 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
763 *out << Verbose(1)
764 << "Calculating the volume of the pyramids formed out of triangles and center of gravity."
765 << endl;
766 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++)
767 { // go through every triangle, calculate volume of its pyramid with CoG as peak
768 x.CopyVector(runner->second->endpoints[0]->node->node);
769 x.SubtractVector(runner->second->endpoints[1]->node->node);
770 y.CopyVector(runner->second->endpoints[0]->node->node);
771 y.SubtractVector(runner->second->endpoints[2]->node->node);
772 a = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
773 b = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[2]->node->node));
774 c = sqrt(runner->second->endpoints[2]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
775 G = sqrt(((a + b + c) * (a + b + c) - 2 * (a * a + b * b + c * c)) / 16.); // area of tesselated triangle
776 x.MakeNormalVector(runner->second->endpoints[0]->node->node, runner->second->endpoints[1]->node->node, runner->second->endpoints[2]->node->node);
777 x.Scale(runner->second->endpoints[1]->node->node->Projection(&x));
778 h = x.Norm(); // distance of CoG to triangle
779 PyramidVolume = (1. / 3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
780 *out << Verbose(2) << "Area of triangle is " << G << " "
781 << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is "
782 << h << " and the volume is " << PyramidVolume << " "
783 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
784 volume += PyramidVolume;
785 }
786 *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10)
787 << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3."
788 << endl;
789
790 return volume;
791}
792;
793
794/** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
795 * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
796 * \param *out output stream for debugging
797 * \param *configuration needed for path to store convex envelope file
798 * \param *mol molecule structure representing the cluster
799 * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead.
800 * \param celldensity desired average density in final cell
801 */
802void
803PrepareClustersinWater(ofstream *out, config *configuration, molecule *mol,
804 double ClusterVolume, double celldensity)
805{
806 // transform to PAS
807 mol->PrincipalAxisSystem(out, true);
808
809 // some preparations beforehand
810 bool IsAngstroem = configuration->GetIsAngstroem();
811 Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol);
812 class Tesselation *TesselStruct = NULL;
813 LinkedCell LCList(mol, 10.);
814 Find_convex_border(out, mol, &LCList, NULL);
815 double clustervolume;
816 if (ClusterVolume == 0)
817 clustervolume = VolumeOfConvexEnvelope(out, TesselStruct, configuration);
818 else
819 clustervolume = ClusterVolume;
820 double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, IsAngstroem);
821 Vector BoxLengths;
822 int repetition[NDIM] =
823 { 1, 1, 1 };
824 int TotalNoClusters = 1;
825 for (int i = 0; i < NDIM; i++)
826 TotalNoClusters *= repetition[i];
827
828 // sum up the atomic masses
829 double totalmass = 0.;
830 atom *Walker = mol->start;
831 while (Walker->next != mol->end)
832 {
833 Walker = Walker->next;
834 totalmass += Walker->type->mass;
835 }
836 *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10)
837 << totalmass << " atomicmassunit." << endl;
838
839 *out << Verbose(0) << "RESULT: The average density is " << setprecision(10)
840 << totalmass / clustervolume << " atomicmassunit/"
841 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
842
843 // solve cubic polynomial
844 *out << Verbose(1) << "Solving equidistant suspension in water problem ..."
845 << endl;
846 double cellvolume;
847 if (IsAngstroem)
848 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_A - (totalmass
849 / clustervolume)) / (celldensity - 1);
850 else
851 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_a0 - (totalmass
852 / clustervolume)) / (celldensity - 1);
853 *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity
854 << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom"
855 : "atomiclength") << "^3." << endl;
856
857 double minimumvolume = TotalNoClusters * (GreatestDiameter[0]
858 * GreatestDiameter[1] * GreatestDiameter[2]);
859 *out << Verbose(1)
860 << "Minimum volume of the convex envelope contained in a rectangular box is "
861 << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom"
862 : "atomiclength") << "^3." << endl;
863 if (minimumvolume > cellvolume)
864 {
865 cerr << Verbose(0)
866 << "ERROR: the containing box already has a greater volume than the envisaged cell volume!"
867 << endl;
868 cout << Verbose(0)
869 << "Setting Box dimensions to minimum possible, the greatest diameters."
870 << endl;
871 for (int i = 0; i < NDIM; i++)
872 BoxLengths.x[i] = GreatestDiameter[i];
873 mol->CenterEdge(out, &BoxLengths);
874 }
875 else
876 {
877 BoxLengths.x[0] = (repetition[0] * GreatestDiameter[0] + repetition[1]
878 * GreatestDiameter[1] + repetition[2] * GreatestDiameter[2]);
879 BoxLengths.x[1] = (repetition[0] * repetition[1] * GreatestDiameter[0]
880 * GreatestDiameter[1] + repetition[0] * repetition[2]
881 * GreatestDiameter[0] * GreatestDiameter[2] + repetition[1]
882 * repetition[2] * GreatestDiameter[1] * GreatestDiameter[2]);
883 BoxLengths.x[2] = minimumvolume - cellvolume;
884 double x0 = 0., x1 = 0., x2 = 0.;
885 if (gsl_poly_solve_cubic(BoxLengths.x[0], BoxLengths.x[1],
886 BoxLengths.x[2], &x0, &x1, &x2) == 1) // either 1 or 3 on return
887 *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0
888 << " ." << endl;
889 else
890 {
891 *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0
892 << " and " << x1 << " and " << x2 << " ." << endl;
893 x0 = x2; // sorted in ascending order
894 }
895
896 cellvolume = 1;
897 for (int i = 0; i < NDIM; i++)
898 {
899 BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]);
900 cellvolume *= BoxLengths.x[i];
901 }
902
903 // set new box dimensions
904 *out << Verbose(0) << "Translating to box with these boundaries." << endl;
905 mol->SetBoxDimension(&BoxLengths);
906 mol->CenterInBox((ofstream *) &cout);
907 }
908 // update Box of atoms by boundary
909 mol->SetBoxDimension(&BoxLengths);
910 *out << Verbose(0) << "RESULT: The resulting cell dimensions are: "
911 << BoxLengths.x[0] << " and " << BoxLengths.x[1] << " and "
912 << BoxLengths.x[2] << " with total volume of " << cellvolume << " "
913 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
914}
915;
916
917
918/** Fills the empty space of the simulation box with water/
919 * \param *out output stream for debugging
920 * \param *List list of molecules already present in box
921 * \param *TesselStruct contains tesselated surface
922 * \param *filler molecule which the box is to be filled with
923 * \param configuration contains box dimensions
924 * \param distance[NDIM] distance between filling molecules in each direction
925 * \param RandAtomDisplacement maximum distance for random displacement per atom
926 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
927 * \param DoRandomRotation true - do random rotiations, false - don't
928 * \return *mol pointer to new molecule with filled atoms
929 */
930molecule * FillBoxWithMolecule(ofstream *out, MoleculeListClass *List, molecule *filler, config &configuration, double distance[NDIM], double RandomAtomDisplacement, double RandomMolDisplacement, bool DoRandomRotation)
931{
932 molecule *Filling = new molecule(filler->elemente);
933 Vector CurrentPosition;
934 int N[NDIM];
935 int n[NDIM];
936 double *M = filler->ReturnFullMatrixforSymmetric(filler->cell_size);
937 double Rotations[NDIM*NDIM];
938 Vector AtomTranslations;
939 Vector FillerTranslations;
940 Vector FillerDistance;
941 double FillIt = false;
942 atom *Walker = NULL;
943 bond *Binder = NULL;
944 int i;
945 LinkedCell *LCList[List->ListOfMolecules.size()];
946
947 *out << Verbose(0) << "Begin of FillBoxWithMolecule" << endl;
948
949 i=0;
950 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
951 *out << Verbose(1) << "Pre-creating linked cell lists for molecule " << *ListRunner << "." << endl;
952 LCList[i] = new LinkedCell((*ListRunner), 5.); // get linked cell list
953 if ((*ListRunner)->TesselStruct == NULL) {
954 *out << Verbose(1) << "Pre-creating tesselation for molecule " << *ListRunner << "." << endl;
955 Find_non_convex_border((ofstream *)&cout, (*ListRunner), LCList[i], NULL, 5.);
956 }
957 i++;
958 }
959
960 // Center filler at origin
961 filler->CenterOrigin(out);
962 filler->Center.Zero();
963
964 filler->CountAtoms(out);
965 atom * CopyAtoms[filler->AtomCount];
966 int nr = 0;
967
968 // calculate filler grid in [0,1]^3
969 FillerDistance.Init(distance[0], distance[1], distance[2]);
970 FillerDistance.InverseMatrixMultiplication(M);
971 *out << Verbose(1) << "INFO: Grid steps are ";
972 for(int i=0;i<NDIM;i++) {
973 N[i] = (int) ceil(1./FillerDistance.x[i]);
974 *out << N[i];
975 if (i != NDIM-1)
976 *out<< ", ";
977 else
978 *out << "." << endl;
979 }
980
981 // go over [0,1]^3 filler grid
982 for (n[0] = 0; n[0] < N[0]; n[0]++)
983 for (n[1] = 0; n[1] < N[1]; n[1]++)
984 for (n[2] = 0; n[2] < N[2]; n[2]++) {
985 // calculate position of current grid vector in untransformed box
986 CurrentPosition.Init((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
987 CurrentPosition.MatrixMultiplication(M);
988 *out << Verbose(2) << "INFO: Current Position is " << CurrentPosition << "." << endl;
989 // Check whether point is in- or outside
990 FillIt = true;
991 i=0;
992 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
993 // get linked cell list
994 if ((*ListRunner)->TesselStruct == NULL) {
995 *out << Verbose(1) << "ERROR: TesselStruct of " << (*ListRunner) << " is NULL. Didn't we pre-create it?" << endl;
996 FillIt = false;
997 } else
998 FillIt = FillIt && (!(*ListRunner)->TesselStruct->IsInnerPoint(out, CurrentPosition, LCList[i++]));
999 }
1000
1001 if (FillIt) {
1002 // fill in Filler
1003 *out << Verbose(2) << "Space at " << CurrentPosition << " is unoccupied by any molecule, filling in." << endl;
1004
1005 // create molecule random translation vector ...
1006 for (int i=0;i<NDIM;i++)
1007 FillerTranslations.x[i] = RandomMolDisplacement*(rand()/(RAND_MAX/2.) - 1.);
1008 *out << Verbose(3) << "INFO: Translating this filler by " << FillerTranslations << "." << endl;
1009
1010 // go through all atoms
1011 nr=0;
1012 Walker = filler->start;
1013 while (Walker->next != filler->end) {
1014 Walker = Walker->next;
1015 // copy atom ...
1016 CopyAtoms[Walker->nr] = new atom(Walker);
1017
1018 // create atomic random translation vector ...
1019 for (int i=0;i<NDIM;i++)
1020 AtomTranslations.x[i] = RandomAtomDisplacement*(rand()/(RAND_MAX/2.) - 1.);
1021
1022 // ... and rotation matrix
1023 if (DoRandomRotation) {
1024 double phi[NDIM];
1025 for (int i=0;i<NDIM;i++) {
1026 phi[i] = rand()/(RAND_MAX/(2.*M_PI));
1027 }
1028
1029 Rotations[0] = cos(phi[0]) *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2]));
1030 Rotations[3] = sin(phi[0]) *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2]));
1031 Rotations[6] = cos(phi[1])*sin(phi[2]) ;
1032 Rotations[1] = - sin(phi[0])*cos(phi[1]) ;
1033 Rotations[4] = cos(phi[0])*cos(phi[1]) ;
1034 Rotations[7] = sin(phi[1]) ;
1035 Rotations[3] = - cos(phi[0]) *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2]));
1036 Rotations[5] = - sin(phi[0]) *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2]));
1037 Rotations[8] = cos(phi[1])*cos(phi[2]) ;
1038 }
1039
1040 // ... and put at new position
1041 if (DoRandomRotation)
1042 CopyAtoms[Walker->nr]->x.MatrixMultiplication(Rotations);
1043 CopyAtoms[Walker->nr]->x.AddVector(&AtomTranslations);
1044 CopyAtoms[Walker->nr]->x.AddVector(&FillerTranslations);
1045 CopyAtoms[Walker->nr]->x.AddVector(&CurrentPosition);
1046
1047 // insert into Filling
1048
1049 // FIXME: gives completely different results if CopyAtoms[..] used instead of Walker, why???
1050 *out << Verbose(4) << "Filling atom " << *Walker << ", translated to " << AtomTranslations << ", at final position is " << (CopyAtoms[Walker->nr]->x) << "." << endl;
1051 Filling->AddAtom(CopyAtoms[Walker->nr]);
1052 }
1053
1054 // go through all bonds and add as well
1055 Binder = filler->first;
1056 while(Binder->next != filler->last) {
1057 Binder = Binder->next;
1058 *out << Verbose(3) << "Adding Bond between " << *CopyAtoms[Binder->leftatom->nr] << " and " << *CopyAtoms[Binder->rightatom->nr]<< "." << endl;
1059 Filling->AddBond(CopyAtoms[Binder->leftatom->nr], CopyAtoms[Binder->rightatom->nr], Binder->BondDegree);
1060 }
1061 } else {
1062 // leave empty
1063 *out << Verbose(2) << "Space at " << CurrentPosition << " is occupied." << endl;
1064 }
1065 }
1066 *out << Verbose(0) << "End of FillBoxWithMolecule" << endl;
1067
1068 return Filling;
1069};
1070
1071
1072/** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
1073 * \param *out output stream for debugging
1074 * \param *mol molecule structure with Atom's and Bond's
1075 * \param *Tess Tesselation filled with points, lines and triangles on boundary on return
1076 * \param *LCList atoms in LinkedCell list
1077 * \param *filename filename prefix for output of vertex data
1078 * \para RADIUS radius of the virtual sphere
1079 */
1080void Find_non_convex_border(ofstream *out, molecule* mol, class LinkedCell *LCList, const char *filename, const double RADIUS)
1081{
1082 int N = 0;
1083 bool freeLC = false;
1084 ofstream *tempstream = NULL;
1085 char NumberName[255];
1086 int TriangleFilesWritten = 0;
1087
1088 *out << Verbose(1) << "Entering search for non convex hull. " << endl;
1089 if (mol->TesselStruct == NULL) {
1090 *out << Verbose(1) << "Allocating Tesselation struct ..." << endl;
1091 mol->TesselStruct = new Tesselation;
1092 } else {
1093 delete(mol->TesselStruct);
1094 *out << Verbose(1) << "Re-Allocating Tesselation struct ..." << endl;
1095 mol->TesselStruct = new Tesselation;
1096 }
1097 LineMap::iterator baseline;
1098 LineMap::iterator testline;
1099 *out << Verbose(0) << "Begin of Find_non_convex_border\n";
1100 bool flag = false; // marks whether we went once through all baselines without finding any without two triangles
1101 bool failflag = false;
1102
1103 if (LCList == NULL) {
1104 LCList = new LinkedCell(mol, 2.*RADIUS);
1105 freeLC = true;
1106 }
1107
1108 mol->TesselStruct->Find_starting_triangle(out, RADIUS, LCList);
1109
1110 baseline = mol->TesselStruct->LinesOnBoundary.begin();
1111 // the outward most line is dangerous, as we may end up with wrapping up the starting triangle, hence
1112 // terminating the algorithm too early.
1113 if (baseline != mol->TesselStruct->LinesOnBoundary.end()) // skip first line as it its the outwardmost!
1114 baseline++;
1115 while ((baseline != mol->TesselStruct->LinesOnBoundary.end()) || (flag)) {
1116 if (baseline->second->triangles.size() == 1) {
1117 failflag = mol->TesselStruct->Find_next_suitable_triangle(out, *(baseline->second), *(((baseline->second->triangles.begin()))->second), RADIUS, N, LCList); //the line is there, so there is a triangle, but only one.
1118 flag = flag || failflag;
1119 if (!failflag)
1120 cerr << "WARNING: Find_next_suitable_triangle failed." << endl;
1121 // write temporary envelope
1122 if ((DoSingleStepOutput && (mol->TesselStruct->TrianglesOnBoundaryCount % SingleStepWidth == 0))) { // if we have a new triangle and want to output each new triangle configuration
1123 TriangleMap::iterator runner = mol->TesselStruct->TrianglesOnBoundary.end();
1124 runner--;
1125 class BoundaryTriangleSet *triangle = runner->second;
1126 if (triangle != NULL) {
1127 sprintf(NumberName, "-%04d-%s_%s_%s", TriangleFilesWritten, triangle->endpoints[0]->node->Name, triangle->endpoints[1]->node->Name, triangle->endpoints[2]->node->Name);
1128 if (DoTecplotOutput) {
1129 string NameofTempFile(filename);
1130 NameofTempFile.append(NumberName);
1131 for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
1132 NameofTempFile.erase(npos, 1);
1133 NameofTempFile.append(TecplotSuffix);
1134 *out << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
1135 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
1136 write_tecplot_file(out, tempstream, mol->TesselStruct, mol, TriangleFilesWritten);
1137 tempstream->close();
1138 tempstream->flush();
1139 delete(tempstream);
1140 }
1141
1142 if (DoRaster3DOutput) {
1143 string NameofTempFile(filename);
1144 NameofTempFile.append(NumberName);
1145 for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
1146 NameofTempFile.erase(npos, 1);
1147 NameofTempFile.append(Raster3DSuffix);
1148 *out << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
1149 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
1150 write_raster3d_file(out, tempstream, mol->TesselStruct, mol);
1151 // // include the current position of the virtual sphere in the temporary raster3d file
1152 // // make the circumsphere's center absolute again
1153 // helper.CopyVector(BaseRay->endpoints[0]->node->node);
1154 // helper.AddVector(BaseRay->endpoints[1]->node->node);
1155 // helper.Scale(0.5);
1156 // (*it)->OptCenter.AddVector(&helper);
1157 // Vector *center = mol->DetermineCenterOfAll(out);
1158 // (*it)->OptCenter.SubtractVector(center);
1159 // delete(center);
1160 // // and add to file plus translucency object
1161 // *tempstream << "# current virtual sphere\n";
1162 // *tempstream << "8\n 25.0 0.6 -1.0 -1.0 -1.0 0.2 0 0 0 0\n";
1163 // *tempstream << "2\n " << (*it)->OptCenter.x[0] << " "
1164 // << (*it)->OptCenter.x[1] << " " << (*it)->OptCenter.x[2]
1165 // << "\t" << RADIUS << "\t1 0 0\n";
1166 // *tempstream << "9\n terminating special property\n";
1167 tempstream->close();
1168 tempstream->flush();
1169 delete(tempstream);
1170 }
1171 }
1172 if (DoTecplotOutput || DoRaster3DOutput)
1173 TriangleFilesWritten++;
1174 }
1175 } else {
1176 //cout << Verbose(1) << "Line " << *baseline->second << " has " << baseline->second->triangles.size() << " triangles adjacent" << endl;
1177 if (baseline->second->triangles.size() != 2)
1178 *out << Verbose(1) << "ERROR: TESSELATION FINISHED WITH INVALID TRIANGLE COUNT!" << endl;
1179 }
1180
1181 N++;
1182 baseline++;
1183 if ((baseline == mol->TesselStruct->LinesOnBoundary.end()) && (flag)) {
1184 baseline = mol->TesselStruct->LinesOnBoundary.begin(); // restart if we reach end due to newly inserted lines
1185 flag = false;
1186 }
1187 }
1188
1189 // write final envelope
1190 if (filename != 0) {
1191 *out << Verbose(1) << "Writing final tecplot file\n";
1192 if (DoTecplotOutput) {
1193 string OutputName(filename);
1194 OutputName.append(TecplotSuffix);
1195 ofstream *tecplot = new ofstream(OutputName.c_str());
1196 write_tecplot_file(out, tecplot, mol->TesselStruct, mol, -1);
1197 tecplot->close();
1198 delete(tecplot);
1199 }
1200 if (DoRaster3DOutput) {
1201 string OutputName(filename);
1202 OutputName.append(Raster3DSuffix);
1203 ofstream *raster = new ofstream(OutputName.c_str());
1204 write_raster3d_file(out, raster, mol->TesselStruct, mol);
1205 raster->close();
1206 delete(raster);
1207 }
1208 } else {
1209 cerr << "ERROR: Could definitively not find all necessary triangles!" << endl;
1210 }
1211
1212 cout << Verbose(2) << "Check: List of Baselines with not two connected triangles:" << endl;
1213 int counter = 0;
1214 for (testline = mol->TesselStruct->LinesOnBoundary.begin(); testline != mol->TesselStruct->LinesOnBoundary.end(); testline++) {
1215 if (testline->second->triangles.size() != 2) {
1216 cout << Verbose(2) << *testline->second << "\t" << testline->second->triangles.size() << endl;
1217 counter++;
1218 }
1219 }
1220 if (counter == 0)
1221 *out << Verbose(2) << "None." << endl;
1222
1223// // Tests the IsInnerAtom() function.
1224// Vector x (0, 0, 0);
1225// *out << Verbose(0) << "Point to check: " << x << endl;
1226// *out << Verbose(0) << "Check: IsInnerPoint() returns " << mol->TesselStruct->IsInnerPoint(out, x, LCList)
1227// << "for vector " << x << "." << endl;
1228// TesselPoint* a = mol->TesselStruct->PointsOnBoundary.begin()->second->node;
1229// *out << Verbose(0) << "Point to check: " << *a << " (on boundary)." << endl;
1230// *out << Verbose(0) << "Check: IsInnerAtom() returns " << mol->TesselStruct->IsInnerPoint(out, a, LCList)
1231// << "for atom " << a << " (on boundary)." << endl;
1232// LinkedNodes *List = NULL;
1233// for (int i=0;i<NDIM;i++) { // each axis
1234// LCList->n[i] = LCList->N[i]-1; // current axis is topmost cell
1235// for (LCList->n[(i+1)%NDIM]=0;LCList->n[(i+1)%NDIM]<LCList->N[(i+1)%NDIM];LCList->n[(i+1)%NDIM]++)
1236// for (LCList->n[(i+2)%NDIM]=0;LCList->n[(i+2)%NDIM]<LCList->N[(i+2)%NDIM];LCList->n[(i+2)%NDIM]++) {
1237// List = LCList->GetCurrentCell();
1238// //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
1239// if (List != NULL) {
1240// for (LinkedNodes::iterator Runner = List->begin();Runner != List->end();Runner++) {
1241// if (mol->TesselStruct->PointsOnBoundary.find((*Runner)->nr) == mol->TesselStruct->PointsOnBoundary.end()) {
1242// a = *Runner;
1243// i=3;
1244// for (int j=0;j<NDIM;j++)
1245// LCList->n[j] = LCList->N[j];
1246// break;
1247// }
1248// }
1249// }
1250// }
1251// }
1252// *out << Verbose(0) << "Check: IsInnerPoint() returns " << mol->TesselStruct->IsInnerPoint(out, a, LCList)
1253// << "for atom " << a << " (inside)." << endl;
1254
1255
1256 if (freeLC)
1257 delete(LCList);
1258 *out << Verbose(0) << "End of Find_non_convex_border\n";
1259};
1260
1261/** Finds a hole of sufficient size in \a this molecule to embed \a *srcmol into it.
1262 * \param *out output stream for debugging
1263 * \param *srcmol molecule to embed into
1264 * \return *Vector new center of \a *srcmol for embedding relative to \a this
1265 */
1266Vector* molecule::FindEmbeddingHole(ofstream *out, molecule *srcmol)
1267{
1268 Vector *Center = new Vector;
1269 Center->Zero();
1270 // calculate volume/shape of \a *srcmol
1271
1272 // find embedding holes
1273
1274 // if more than one, let user choose
1275
1276 // return embedding center
1277 return Center;
1278};
1279
Note: See TracBrowser for help on using the repository browser.