source: src/boundary.cpp@ 133d56

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

output of terminating special property comment in .r3d file had no "#" in front.

  • Property mode set to 100755
File size: 50.1 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) {
232 *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl;
233 *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl;
234 *tecplot << "ZONE T=\"TRIANGLES" << N << "\", N=" << TesselStruct->PointsOnBoundaryCount << ", E=" << TesselStruct->TrianglesOnBoundaryCount << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl;
235 int *LookupList = new int[mol->AtomCount];
236 for (int i = 0; i < mol->AtomCount; i++)
237 LookupList[i] = -1;
238
239 // print atom coordinates
240 *out << Verbose(2) << "The following triangles were created:";
241 int Counter = 1;
242 TesselPoint *Walker = NULL;
243 for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target != TesselStruct->PointsOnBoundary.end(); target++) {
244 Walker = target->second->node;
245 LookupList[Walker->nr] = Counter++;
246 *tecplot << Walker->node->x[0] << " " << Walker->node->x[1] << " " << Walker->node->x[2] << " " << endl;
247 }
248 *tecplot << endl;
249 // print connectivity
250 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++) {
251 *out << " " << runner->second->endpoints[0]->node->Name << "<->" << runner->second->endpoints[1]->node->Name << "<->" << runner->second->endpoints[2]->node->Name;
252 *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " " << LookupList[runner->second->endpoints[1]->node->nr] << " " << LookupList[runner->second->endpoints[2]->node->nr] << endl;
253 }
254 delete[] (LookupList);
255 *out << endl;
256 }
257}
258
259
260/** Determines the boundary points of a cluster.
261 * Does a projection per axis onto the orthogonal plane, transforms into spherical coordinates, sorts them by the angle
262 * and looks at triples: if the middle has less a distance than the allowed maximum height of the triangle formed by the plane's
263 * center and first and last point in the triple, it is thrown out.
264 * \param *out output stream for debugging
265 * \param *mol molecule structure representing the cluster
266 */
267Boundaries *GetBoundaryPoints(ofstream *out, molecule *mol)
268{
269 atom *Walker = NULL;
270 PointMap PointsOnBoundary;
271 LineMap LinesOnBoundary;
272 TriangleMap TrianglesOnBoundary;
273 Vector *MolCenter = mol->DetermineCenterOfAll(out);
274 Vector helper;
275
276 *out << Verbose(1) << "Finding all boundary points." << endl;
277 Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, nr)
278 BoundariesTestPair BoundaryTestPair;
279 Vector AxisVector, AngleReferenceVector, AngleReferenceNormalVector;
280 double radius, angle;
281 // 3a. Go through every axis
282 for (int axis = 0; axis < NDIM; axis++) {
283 AxisVector.Zero();
284 AngleReferenceVector.Zero();
285 AngleReferenceNormalVector.Zero();
286 AxisVector.x[axis] = 1.;
287 AngleReferenceVector.x[(axis + 1) % NDIM] = 1.;
288 AngleReferenceNormalVector.x[(axis + 2) % NDIM] = 1.;
289
290 *out << Verbose(1) << "Axisvector is " << AxisVector << " and AngleReferenceVector is " << AngleReferenceVector << ", and AngleReferenceNormalVector is " << AngleReferenceNormalVector << "." << endl;
291
292 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
293 Walker = mol->start;
294 while (Walker->next != mol->end) {
295 Walker = Walker->next;
296 Vector ProjectedVector;
297 ProjectedVector.CopyVector(&Walker->x);
298 ProjectedVector.SubtractVector(MolCenter);
299 ProjectedVector.ProjectOntoPlane(&AxisVector);
300
301 // correct for negative side
302 radius = ProjectedVector.NormSquared();
303 if (fabs(radius) > MYEPSILON)
304 angle = ProjectedVector.Angle(&AngleReferenceVector);
305 else
306 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
307
308 //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl;
309 if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0) {
310 angle = 2. * M_PI - angle;
311 }
312 *out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): " << ProjectedVector << endl;
313 BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle, DistancePair (radius, Walker)));
314 if (!BoundaryTestPair.second) { // same point exists, check first r, then distance of original vectors to center of gravity
315 *out << Verbose(2) << "Encountered two vectors whose projection onto axis " << axis << " is equal: " << endl;
316 *out << Verbose(2) << "Present vector: " << *BoundaryTestPair.first->second.second << endl;
317 *out << Verbose(2) << "New vector: " << *Walker << endl;
318 double tmp = ProjectedVector.NormSquared();
319 if ((tmp - BoundaryTestPair.first->second.first) > MYEPSILON) {
320 BoundaryTestPair.first->second.first = tmp;
321 BoundaryTestPair.first->second.second = Walker;
322 *out << Verbose(2) << "Keeping new vector due to larger projected distance " << tmp << "." << endl;
323 } else if (fabs(tmp - BoundaryTestPair.first->second.first) < MYEPSILON) {
324 helper.CopyVector(&Walker->x);
325 helper.SubtractVector(MolCenter);
326 tmp = helper.NormSquared();
327 helper.CopyVector(&BoundaryTestPair.first->second.second->x);
328 helper.SubtractVector(MolCenter);
329 if (helper.NormSquared() < tmp) {
330 BoundaryTestPair.first->second.second = Walker;
331 *out << Verbose(2) << "Keeping new vector due to larger distance to molecule center " << helper.NormSquared() << "." << endl;
332 } else {
333 *out << Verbose(2) << "Keeping present vector due to larger distance to molecule center " << tmp << "." << endl;
334 }
335 } else {
336 *out << Verbose(2) << "Keeping present vector due to larger projected distance " << tmp << "." << endl;
337 }
338 }
339 }
340 // printing all inserted for debugging
341 // {
342 // *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
343 // int i=0;
344 // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
345 // if (runner != BoundaryPoints[axis].begin())
346 // *out << ", " << i << ": " << *runner->second.second;
347 // else
348 // *out << i << ": " << *runner->second.second;
349 // i++;
350 // }
351 // *out << endl;
352 // }
353 // 3c. throw out points whose distance is less than the mean of left and right neighbours
354 bool flag = false;
355 *out << Verbose(1) << "Looking for candidates to kick out by convex condition ... " << endl;
356 do { // do as long as we still throw one out per round
357 flag = false;
358 Boundaries::iterator left = BoundaryPoints[axis].end();
359 Boundaries::iterator right = BoundaryPoints[axis].end();
360 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
361 // set neighbours correctly
362 if (runner == BoundaryPoints[axis].begin()) {
363 left = BoundaryPoints[axis].end();
364 } else {
365 left = runner;
366 }
367 left--;
368 right = runner;
369 right++;
370 if (right == BoundaryPoints[axis].end()) {
371 right = BoundaryPoints[axis].begin();
372 }
373 // check distance
374
375 // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)
376 {
377 Vector SideA, SideB, SideC, SideH;
378 SideA.CopyVector(&left->second.second->x);
379 SideA.SubtractVector(MolCenter);
380 SideA.ProjectOntoPlane(&AxisVector);
381 // *out << "SideA: ";
382 // SideA.Output(out);
383 // *out << endl;
384
385 SideB.CopyVector(&right->second.second->x);
386 SideB.SubtractVector(MolCenter);
387 SideB.ProjectOntoPlane(&AxisVector);
388 // *out << "SideB: ";
389 // SideB.Output(out);
390 // *out << endl;
391
392 SideC.CopyVector(&left->second.second->x);
393 SideC.SubtractVector(&right->second.second->x);
394 SideC.ProjectOntoPlane(&AxisVector);
395 // *out << "SideC: ";
396 // SideC.Output(out);
397 // *out << endl;
398
399 SideH.CopyVector(&runner->second.second->x);
400 SideH.SubtractVector(MolCenter);
401 SideH.ProjectOntoPlane(&AxisVector);
402 // *out << "SideH: ";
403 // SideH.Output(out);
404 // *out << endl;
405
406 // calculate each length
407 double a = SideA.Norm();
408 //double b = SideB.Norm();
409 //double c = SideC.Norm();
410 double h = SideH.Norm();
411 // calculate the angles
412 double alpha = SideA.Angle(&SideH);
413 double beta = SideA.Angle(&SideC);
414 double gamma = SideB.Angle(&SideH);
415 double delta = SideC.Angle(&SideH);
416 double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.);
417 //*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;
418 *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;
419 if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance)) < MYEPSILON) && ((h - MinDistance)) < -MYEPSILON) {
420 // throw out point
421 *out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl;
422 BoundaryPoints[axis].erase(runner);
423 flag = true;
424 }
425 }
426 }
427 } while (flag);
428 }
429 delete(MolCenter);
430 return BoundaryPoints;
431};
432
433/** Tesselates the convex boundary by finding all boundary points.
434 * \param *out output stream for debugging
435 * \param *mol molecule structure with Atom's and Bond's
436 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
437 * \param *LCList atoms in LinkedCell list
438 * \param *filename filename prefix for output of vertex data
439 * \return *TesselStruct is filled with convex boundary and tesselation is stored under \a *filename.
440 */
441void Find_convex_border(ofstream *out, molecule* mol, class LinkedCell *LCList, const char *filename)
442{
443 bool BoundaryFreeFlag = false;
444 Boundaries *BoundaryPoints = NULL;
445
446 cout << Verbose(1) << "Begin of find_convex_border" << endl;
447
448 if (mol->TesselStruct != NULL) // free if allocated
449 delete(mol->TesselStruct);
450 mol->TesselStruct = new class Tesselation;
451
452 // 1. Find all points on the boundary
453 if (BoundaryPoints == NULL) {
454 BoundaryFreeFlag = true;
455 BoundaryPoints = GetBoundaryPoints(out, mol);
456 } else {
457 *out << Verbose(1) << "Using given boundary points set." << endl;
458 }
459
460// printing all inserted for debugging
461 for (int axis=0; axis < NDIM; axis++)
462 {
463 *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
464 int i=0;
465 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
466 if (runner != BoundaryPoints[axis].begin())
467 *out << ", " << i << ": " << *runner->second.second;
468 else
469 *out << i << ": " << *runner->second.second;
470 i++;
471 }
472 *out << endl;
473 }
474
475 // 2. fill the boundary point list
476 for (int axis = 0; axis < NDIM; axis++)
477 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++)
478 mol->TesselStruct->AddPoint(runner->second.second);
479
480 *out << Verbose(2) << "I found " << mol->TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl;
481 // now we have the whole set of edge points in the BoundaryList
482
483 // listing for debugging
484 // *out << Verbose(1) << "Listing PointsOnBoundary:";
485 // for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
486 // *out << " " << *runner->second;
487 // }
488 // *out << endl;
489
490 // 3a. guess starting triangle
491 mol->TesselStruct->GuessStartingTriangle(out);
492
493 // 3b. go through all lines, that are not yet part of two triangles (only of one so far)
494 mol->TesselStruct->TesselateOnBoundary(out, mol);
495
496 // 3c. check whether all atoms lay inside the boundary, if not, add to boundary points, segment triangle into three with the new point
497 if (!mol->TesselStruct->InsertStraddlingPoints(out, mol, LCList))
498 *out << Verbose(1) << "Insertion of straddling points failed!" << endl;
499
500 *out << Verbose(2) << "I created " << mol->TesselStruct->TrianglesOnBoundary.size() << " intermediate triangles with " << mol->TesselStruct->LinesOnBoundary.size() << " lines and " << mol->TesselStruct->PointsOnBoundary.size() << " points." << endl;
501
502 // 4. Store triangles in tecplot file
503 if (filename != NULL) {
504 if (DoTecplotOutput) {
505 string OutputName(filename);
506 OutputName.append("_intermed");
507 OutputName.append(TecplotSuffix);
508 ofstream *tecplot = new ofstream(OutputName.c_str());
509 write_tecplot_file(out, tecplot, mol->TesselStruct, mol, 0);
510 tecplot->close();
511 delete(tecplot);
512 }
513 if (DoRaster3DOutput) {
514 string OutputName(filename);
515 OutputName.append("_intermed");
516 OutputName.append(Raster3DSuffix);
517 ofstream *rasterplot = new ofstream(OutputName.c_str());
518 write_raster3d_file(out, rasterplot, mol->TesselStruct, mol);
519 rasterplot->close();
520 delete(rasterplot);
521 }
522 }
523
524 // 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
525 if (!mol->TesselStruct->CorrectConcaveBaselines(out))
526 *out << Verbose(1) << "Correction of concave baselines failed!" << endl;
527
528 // 3e. we need another correction here, for TesselPoints that are below the surface (i.e. have an odd number of concave triangles surrounding it)
529// if (!mol->TesselStruct->CorrectConcaveTesselPoints(out))
530// *out << Verbose(1) << "Correction of concave tesselpoints failed!" << endl;
531
532 *out << Verbose(2) << "I created " << mol->TesselStruct->TrianglesOnBoundary.size() << " triangles with " << mol->TesselStruct->LinesOnBoundary.size() << " lines and " << mol->TesselStruct->PointsOnBoundary.size() << " points." << endl;
533
534 // 4. Store triangles in tecplot file
535 if (filename != NULL) {
536 if (DoTecplotOutput) {
537 string OutputName(filename);
538 OutputName.append(TecplotSuffix);
539 ofstream *tecplot = new ofstream(OutputName.c_str());
540 write_tecplot_file(out, tecplot, mol->TesselStruct, mol, 0);
541 tecplot->close();
542 delete(tecplot);
543 }
544 if (DoRaster3DOutput) {
545 string OutputName(filename);
546 OutputName.append(Raster3DSuffix);
547 ofstream *rasterplot = new ofstream(OutputName.c_str());
548 write_raster3d_file(out, rasterplot, mol->TesselStruct, mol);
549 rasterplot->close();
550 delete(rasterplot);
551 }
552 }
553
554
555 // free reference lists
556 if (BoundaryFreeFlag)
557 delete[] (BoundaryPoints);
558
559 cout << Verbose(1) << "End of find_convex_border" << endl;
560};
561
562
563/** Determines the volume of a cluster.
564 * Determines first the convex envelope, then tesselates it and calculates its volume.
565 * \param *out output stream for debugging
566 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
567 * \param *configuration needed for path to store convex envelope file
568 * \return determined volume of the cluster in cubed config:GetIsAngstroem()
569 */
570double VolumeOfConvexEnvelope(ofstream *out, class Tesselation *TesselStruct, class config *configuration)
571{
572 bool IsAngstroem = configuration->GetIsAngstroem();
573 double volume = 0.;
574 double PyramidVolume = 0.;
575 double G, h;
576 Vector x, y;
577 double a, b, c;
578
579 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
580 *out << Verbose(1)
581 << "Calculating the volume of the pyramids formed out of triangles and center of gravity."
582 << endl;
583 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++)
584 { // go through every triangle, calculate volume of its pyramid with CoG as peak
585 x.CopyVector(runner->second->endpoints[0]->node->node);
586 x.SubtractVector(runner->second->endpoints[1]->node->node);
587 y.CopyVector(runner->second->endpoints[0]->node->node);
588 y.SubtractVector(runner->second->endpoints[2]->node->node);
589 a = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
590 b = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[2]->node->node));
591 c = sqrt(runner->second->endpoints[2]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
592 G = sqrt(((a + b + c) * (a + b + c) - 2 * (a * a + b * b + c * c)) / 16.); // area of tesselated triangle
593 x.MakeNormalVector(runner->second->endpoints[0]->node->node, runner->second->endpoints[1]->node->node, runner->second->endpoints[2]->node->node);
594 x.Scale(runner->second->endpoints[1]->node->node->Projection(&x));
595 h = x.Norm(); // distance of CoG to triangle
596 PyramidVolume = (1. / 3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
597 *out << Verbose(2) << "Area of triangle is " << G << " "
598 << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is "
599 << h << " and the volume is " << PyramidVolume << " "
600 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
601 volume += PyramidVolume;
602 }
603 *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10)
604 << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3."
605 << endl;
606
607 return volume;
608}
609;
610
611/** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
612 * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
613 * \param *out output stream for debugging
614 * \param *configuration needed for path to store convex envelope file
615 * \param *mol molecule structure representing the cluster
616 * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead.
617 * \param celldensity desired average density in final cell
618 */
619void
620PrepareClustersinWater(ofstream *out, config *configuration, molecule *mol,
621 double ClusterVolume, double celldensity)
622{
623 // transform to PAS
624 mol->PrincipalAxisSystem(out, true);
625
626 // some preparations beforehand
627 bool IsAngstroem = configuration->GetIsAngstroem();
628 Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol);
629 class Tesselation *TesselStruct = NULL;
630 LinkedCell LCList(mol, 10.);
631 Find_convex_border(out, mol, &LCList, NULL);
632 double clustervolume;
633 if (ClusterVolume == 0)
634 clustervolume = VolumeOfConvexEnvelope(out, TesselStruct, configuration);
635 else
636 clustervolume = ClusterVolume;
637 double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, IsAngstroem);
638 Vector BoxLengths;
639 int repetition[NDIM] =
640 { 1, 1, 1 };
641 int TotalNoClusters = 1;
642 for (int i = 0; i < NDIM; i++)
643 TotalNoClusters *= repetition[i];
644
645 // sum up the atomic masses
646 double totalmass = 0.;
647 atom *Walker = mol->start;
648 while (Walker->next != mol->end)
649 {
650 Walker = Walker->next;
651 totalmass += Walker->type->mass;
652 }
653 *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10)
654 << totalmass << " atomicmassunit." << endl;
655
656 *out << Verbose(0) << "RESULT: The average density is " << setprecision(10)
657 << totalmass / clustervolume << " atomicmassunit/"
658 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
659
660 // solve cubic polynomial
661 *out << Verbose(1) << "Solving equidistant suspension in water problem ..."
662 << endl;
663 double cellvolume;
664 if (IsAngstroem)
665 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_A - (totalmass
666 / clustervolume)) / (celldensity - 1);
667 else
668 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_a0 - (totalmass
669 / clustervolume)) / (celldensity - 1);
670 *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity
671 << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom"
672 : "atomiclength") << "^3." << endl;
673
674 double minimumvolume = TotalNoClusters * (GreatestDiameter[0]
675 * GreatestDiameter[1] * GreatestDiameter[2]);
676 *out << Verbose(1)
677 << "Minimum volume of the convex envelope contained in a rectangular box is "
678 << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom"
679 : "atomiclength") << "^3." << endl;
680 if (minimumvolume > cellvolume)
681 {
682 cerr << Verbose(0)
683 << "ERROR: the containing box already has a greater volume than the envisaged cell volume!"
684 << endl;
685 cout << Verbose(0)
686 << "Setting Box dimensions to minimum possible, the greatest diameters."
687 << endl;
688 for (int i = 0; i < NDIM; i++)
689 BoxLengths.x[i] = GreatestDiameter[i];
690 mol->CenterEdge(out, &BoxLengths);
691 }
692 else
693 {
694 BoxLengths.x[0] = (repetition[0] * GreatestDiameter[0] + repetition[1]
695 * GreatestDiameter[1] + repetition[2] * GreatestDiameter[2]);
696 BoxLengths.x[1] = (repetition[0] * repetition[1] * GreatestDiameter[0]
697 * GreatestDiameter[1] + repetition[0] * repetition[2]
698 * GreatestDiameter[0] * GreatestDiameter[2] + repetition[1]
699 * repetition[2] * GreatestDiameter[1] * GreatestDiameter[2]);
700 BoxLengths.x[2] = minimumvolume - cellvolume;
701 double x0 = 0., x1 = 0., x2 = 0.;
702 if (gsl_poly_solve_cubic(BoxLengths.x[0], BoxLengths.x[1],
703 BoxLengths.x[2], &x0, &x1, &x2) == 1) // either 1 or 3 on return
704 *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0
705 << " ." << endl;
706 else
707 {
708 *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0
709 << " and " << x1 << " and " << x2 << " ." << endl;
710 x0 = x2; // sorted in ascending order
711 }
712
713 cellvolume = 1;
714 for (int i = 0; i < NDIM; i++)
715 {
716 BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]);
717 cellvolume *= BoxLengths.x[i];
718 }
719
720 // set new box dimensions
721 *out << Verbose(0) << "Translating to box with these boundaries." << endl;
722 mol->SetBoxDimension(&BoxLengths);
723 mol->CenterInBox((ofstream *) &cout);
724 }
725 // update Box of atoms by boundary
726 mol->SetBoxDimension(&BoxLengths);
727 *out << Verbose(0) << "RESULT: The resulting cell dimensions are: "
728 << BoxLengths.x[0] << " and " << BoxLengths.x[1] << " and "
729 << BoxLengths.x[2] << " with total volume of " << cellvolume << " "
730 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
731}
732;
733
734
735/** Fills the empty space of the simulation box with water/
736 * \param *out output stream for debugging
737 * \param *List list of molecules already present in box
738 * \param *TesselStruct contains tesselated surface
739 * \param *filler molecule which the box is to be filled with
740 * \param configuration contains box dimensions
741 * \param distance[NDIM] distance between filling molecules in each direction
742 * \param RandAtomDisplacement maximum distance for random displacement per atom
743 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
744 * \param DoRandomRotation true - do random rotiations, false - don't
745 * \return *mol pointer to new molecule with filled atoms
746 */
747molecule * FillBoxWithMolecule(ofstream *out, MoleculeListClass *List, molecule *filler, config &configuration, double distance[NDIM], double RandomAtomDisplacement, double RandomMolDisplacement, bool DoRandomRotation)
748{
749 molecule *Filling = new molecule(filler->elemente);
750 Vector CurrentPosition;
751 int N[NDIM];
752 int n[NDIM];
753 double *M = filler->ReturnFullMatrixforSymmetric(filler->cell_size);
754 double Rotations[NDIM*NDIM];
755 Vector AtomTranslations;
756 Vector FillerTranslations;
757 Vector FillerDistance;
758 double FillIt = false;
759 atom *Walker = NULL;
760 bond *Binder = NULL;
761 int i;
762 LinkedCell *LCList[List->ListOfMolecules.size()];
763
764 *out << Verbose(0) << "Begin of FillBoxWithMolecule" << endl;
765
766 i=0;
767 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
768 *out << Verbose(1) << "Pre-creating linked cell lists for molecule " << *ListRunner << "." << endl;
769 LCList[i] = new LinkedCell((*ListRunner), 5.); // get linked cell list
770 if ((*ListRunner)->TesselStruct == NULL) {
771 *out << Verbose(1) << "Pre-creating tesselation for molecule " << *ListRunner << "." << endl;
772 Find_non_convex_border((ofstream *)&cout, (*ListRunner), LCList[i], NULL, 5.);
773 }
774 i++;
775 }
776
777 // Center filler at origin
778 filler->CenterOrigin(out);
779 filler->Center.Zero();
780
781 filler->CountAtoms(out);
782 atom * CopyAtoms[filler->AtomCount];
783 int nr = 0;
784
785 // calculate filler grid in [0,1]^3
786 FillerDistance.Init(distance[0], distance[1], distance[2]);
787 FillerDistance.InverseMatrixMultiplication(M);
788 *out << Verbose(1) << "INFO: Grid steps are ";
789 for(int i=0;i<NDIM;i++) {
790 N[i] = (int) ceil(1./FillerDistance.x[i]);
791 *out << N[i];
792 if (i != NDIM-1)
793 *out<< ", ";
794 else
795 *out << "." << endl;
796 }
797
798 // go over [0,1]^3 filler grid
799 for (n[0] = 0; n[0] < N[0]; n[0]++)
800 for (n[1] = 0; n[1] < N[1]; n[1]++)
801 for (n[2] = 0; n[2] < N[2]; n[2]++) {
802 // calculate position of current grid vector in untransformed box
803 CurrentPosition.Init((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
804 CurrentPosition.MatrixMultiplication(M);
805 *out << Verbose(2) << "INFO: Current Position is " << CurrentPosition << "." << endl;
806 // Check whether point is in- or outside
807 FillIt = true;
808 i=0;
809 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
810 // get linked cell list
811 if ((*ListRunner)->TesselStruct == NULL) {
812 *out << Verbose(1) << "ERROR: TesselStruct of " << (*ListRunner) << " is NULL. Didn't we pre-create it?" << endl;
813 FillIt = false;
814 } else
815 FillIt = FillIt && (!(*ListRunner)->TesselStruct->IsInnerPoint(out, CurrentPosition, LCList[i++]));
816 }
817
818 if (FillIt) {
819 // fill in Filler
820 *out << Verbose(2) << "Space at " << CurrentPosition << " is unoccupied by any molecule, filling in." << endl;
821
822 // create molecule random translation vector ...
823 for (int i=0;i<NDIM;i++)
824 FillerTranslations.x[i] = RandomMolDisplacement*(rand()/(RAND_MAX/2.) - 1.);
825 *out << Verbose(3) << "INFO: Translating this filler by " << FillerTranslations << "." << endl;
826
827 // go through all atoms
828 nr=0;
829 Walker = filler->start;
830 while (Walker->next != filler->end) {
831 Walker = Walker->next;
832 // copy atom ...
833 CopyAtoms[Walker->nr] = new atom(Walker);
834
835 // create atomic random translation vector ...
836 for (int i=0;i<NDIM;i++)
837 AtomTranslations.x[i] = RandomAtomDisplacement*(rand()/(RAND_MAX/2.) - 1.);
838
839 // ... and rotation matrix
840 if (DoRandomRotation) {
841 double phi[NDIM];
842 for (int i=0;i<NDIM;i++) {
843 phi[i] = rand()/(RAND_MAX/(2.*M_PI));
844 }
845
846 Rotations[0] = cos(phi[0]) *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2]));
847 Rotations[3] = sin(phi[0]) *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2]));
848 Rotations[6] = cos(phi[1])*sin(phi[2]) ;
849 Rotations[1] = - sin(phi[0])*cos(phi[1]) ;
850 Rotations[4] = cos(phi[0])*cos(phi[1]) ;
851 Rotations[7] = sin(phi[1]) ;
852 Rotations[3] = - cos(phi[0]) *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2]));
853 Rotations[5] = - sin(phi[0]) *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2]));
854 Rotations[8] = cos(phi[1])*cos(phi[2]) ;
855 }
856
857 // ... and put at new position
858 if (DoRandomRotation)
859 CopyAtoms[Walker->nr]->x.MatrixMultiplication(Rotations);
860 CopyAtoms[Walker->nr]->x.AddVector(&AtomTranslations);
861 CopyAtoms[Walker->nr]->x.AddVector(&FillerTranslations);
862 CopyAtoms[Walker->nr]->x.AddVector(&CurrentPosition);
863
864 // insert into Filling
865
866 // FIXME: gives completely different results if CopyAtoms[..] used instead of Walker, why???
867 *out << Verbose(4) << "Filling atom " << *Walker << ", translated to " << AtomTranslations << ", at final position is " << (CopyAtoms[Walker->nr]->x) << "." << endl;
868 Filling->AddAtom(CopyAtoms[Walker->nr]);
869 }
870
871 // go through all bonds and add as well
872 Binder = filler->first;
873 while(Binder->next != filler->last) {
874 Binder = Binder->next;
875 *out << Verbose(3) << "Adding Bond between " << *CopyAtoms[Binder->leftatom->nr] << " and " << *CopyAtoms[Binder->rightatom->nr]<< "." << endl;
876 Filling->AddBond(CopyAtoms[Binder->leftatom->nr], CopyAtoms[Binder->rightatom->nr], Binder->BondDegree);
877 }
878 } else {
879 // leave empty
880 *out << Verbose(2) << "Space at " << CurrentPosition << " is occupied." << endl;
881 }
882 }
883 *out << Verbose(0) << "End of FillBoxWithMolecule" << endl;
884
885 return Filling;
886};
887
888
889/** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
890 * \param *out output stream for debugging
891 * \param *mol molecule structure with Atom's and Bond's
892 * \param *Tess Tesselation filled with points, lines and triangles on boundary on return
893 * \param *LCList atoms in LinkedCell list
894 * \param *filename filename prefix for output of vertex data
895 * \para RADIUS radius of the virtual sphere
896 */
897void Find_non_convex_border(ofstream *out, molecule* mol, class LinkedCell *LCList, const char *filename, const double RADIUS)
898{
899 int N = 0;
900 bool freeLC = false;
901 ofstream *tempstream = NULL;
902 char NumberName[255];
903 int TriangleFilesWritten = 0;
904
905 *out << Verbose(1) << "Entering search for non convex hull. " << endl;
906 if (mol->TesselStruct == NULL) {
907 *out << Verbose(1) << "Allocating Tesselation struct ..." << endl;
908 mol->TesselStruct = new Tesselation;
909 } else {
910 delete(mol->TesselStruct);
911 *out << Verbose(1) << "Re-Allocating Tesselation struct ..." << endl;
912 mol->TesselStruct = new Tesselation;
913 }
914 LineMap::iterator baseline;
915 LineMap::iterator testline;
916 *out << Verbose(0) << "Begin of Find_non_convex_border\n";
917 bool flag = false; // marks whether we went once through all baselines without finding any without two triangles
918 bool failflag = false;
919
920 if (LCList == NULL) {
921 LCList = new LinkedCell(mol, 2.*RADIUS);
922 freeLC = true;
923 }
924
925 mol->TesselStruct->Find_starting_triangle(out, RADIUS, LCList);
926
927 baseline = mol->TesselStruct->LinesOnBoundary.begin();
928 while ((baseline != mol->TesselStruct->LinesOnBoundary.end()) || (flag)) {
929 if (baseline->second->TrianglesCount == 1) {
930 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.
931 flag = flag || failflag;
932 if (!failflag)
933 cerr << "WARNING: Find_next_suitable_triangle failed." << endl;
934 // write temporary envelope
935 if ((DoSingleStepOutput && (mol->TesselStruct->TrianglesOnBoundaryCount % SingleStepWidth == 0))) { // if we have a new triangle and want to output each new triangle configuration
936 TriangleMap::iterator runner = mol->TesselStruct->TrianglesOnBoundary.end();
937 runner--;
938 class BoundaryTriangleSet *triangle = runner->second;
939 if (triangle != NULL) {
940 sprintf(NumberName, "-%04d-%s_%s_%s", TriangleFilesWritten, triangle->endpoints[0]->node->Name, triangle->endpoints[1]->node->Name, triangle->endpoints[2]->node->Name);
941 if (DoTecplotOutput) {
942 string NameofTempFile(filename);
943 NameofTempFile.append(NumberName);
944 for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
945 NameofTempFile.erase(npos, 1);
946 NameofTempFile.append(TecplotSuffix);
947 *out << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
948 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
949 write_tecplot_file(out, tempstream, mol->TesselStruct, mol, TriangleFilesWritten);
950 tempstream->close();
951 tempstream->flush();
952 delete(tempstream);
953 }
954
955 if (DoRaster3DOutput) {
956 string NameofTempFile(filename);
957 NameofTempFile.append(NumberName);
958 for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
959 NameofTempFile.erase(npos, 1);
960 NameofTempFile.append(Raster3DSuffix);
961 *out << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
962 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
963 write_raster3d_file(out, tempstream, mol->TesselStruct, mol);
964 // // include the current position of the virtual sphere in the temporary raster3d file
965 // // make the circumsphere's center absolute again
966 // helper.CopyVector(BaseRay->endpoints[0]->node->node);
967 // helper.AddVector(BaseRay->endpoints[1]->node->node);
968 // helper.Scale(0.5);
969 // (*it)->OptCenter.AddVector(&helper);
970 // Vector *center = mol->DetermineCenterOfAll(out);
971 // (*it)->OptCenter.SubtractVector(center);
972 // delete(center);
973 // // and add to file plus translucency object
974 // *tempstream << "# current virtual sphere\n";
975 // *tempstream << "8\n 25.0 0.6 -1.0 -1.0 -1.0 0.2 0 0 0 0\n";
976 // *tempstream << "2\n " << (*it)->OptCenter.x[0] << " "
977 // << (*it)->OptCenter.x[1] << " " << (*it)->OptCenter.x[2]
978 // << "\t" << RADIUS << "\t1 0 0\n";
979 // *tempstream << "9\n terminating special property\n";
980 tempstream->close();
981 tempstream->flush();
982 delete(tempstream);
983 }
984 }
985 if (DoTecplotOutput || DoRaster3DOutput)
986 TriangleFilesWritten++;
987 }
988 } else {
989 //cout << Verbose(1) << "Line " << *baseline->second << " has " << baseline->second->TrianglesCount << " triangles adjacent" << endl;
990 if (baseline->second->TrianglesCount != 2)
991 *out << Verbose(1) << "ERROR: TESSELATION FINISHED WITH INVALID TRIANGLE COUNT!" << endl;
992 }
993
994 N++;
995 baseline++;
996 if ((baseline == mol->TesselStruct->LinesOnBoundary.end()) && (flag)) {
997 baseline = mol->TesselStruct->LinesOnBoundary.begin(); // restart if we reach end due to newly inserted lines
998 flag = false;
999 }
1000 }
1001
1002 // write final envelope
1003 if (filename != 0) {
1004 *out << Verbose(1) << "Writing final tecplot file\n";
1005 if (DoTecplotOutput) {
1006 string OutputName(filename);
1007 OutputName.append(TecplotSuffix);
1008 ofstream *tecplot = new ofstream(OutputName.c_str());
1009 write_tecplot_file(out, tecplot, mol->TesselStruct, mol, -1);
1010 tecplot->close();
1011 delete(tecplot);
1012 }
1013 if (DoRaster3DOutput) {
1014 string OutputName(filename);
1015 OutputName.append(Raster3DSuffix);
1016 ofstream *raster = new ofstream(OutputName.c_str());
1017 write_raster3d_file(out, raster, mol->TesselStruct, mol);
1018 raster->close();
1019 delete(raster);
1020 }
1021 } else {
1022 cerr << "ERROR: Could definitively not find all necessary triangles!" << endl;
1023 }
1024
1025 cout << Verbose(2) << "Check: List of Baselines with not two connected triangles:" << endl;
1026 int counter = 0;
1027 for (testline = mol->TesselStruct->LinesOnBoundary.begin(); testline != mol->TesselStruct->LinesOnBoundary.end(); testline++) {
1028 if (testline->second->TrianglesCount != 2) {
1029 cout << Verbose(2) << *testline->second << "\t" << testline->second->TrianglesCount << endl;
1030 counter++;
1031 }
1032 }
1033 if (counter == 0)
1034 *out << Verbose(2) << "None." << endl;
1035
1036// // Tests the IsInnerAtom() function.
1037// Vector x (0, 0, 0);
1038// *out << Verbose(0) << "Point to check: " << x << endl;
1039// *out << Verbose(0) << "Check: IsInnerPoint() returns " << mol->TesselStruct->IsInnerPoint(out, x, LCList)
1040// << "for vector " << x << "." << endl;
1041// TesselPoint* a = mol->TesselStruct->PointsOnBoundary.begin()->second->node;
1042// *out << Verbose(0) << "Point to check: " << *a << " (on boundary)." << endl;
1043// *out << Verbose(0) << "Check: IsInnerAtom() returns " << mol->TesselStruct->IsInnerPoint(out, a, LCList)
1044// << "for atom " << a << " (on boundary)." << endl;
1045// LinkedNodes *List = NULL;
1046// for (int i=0;i<NDIM;i++) { // each axis
1047// LCList->n[i] = LCList->N[i]-1; // current axis is topmost cell
1048// for (LCList->n[(i+1)%NDIM]=0;LCList->n[(i+1)%NDIM]<LCList->N[(i+1)%NDIM];LCList->n[(i+1)%NDIM]++)
1049// for (LCList->n[(i+2)%NDIM]=0;LCList->n[(i+2)%NDIM]<LCList->N[(i+2)%NDIM];LCList->n[(i+2)%NDIM]++) {
1050// List = LCList->GetCurrentCell();
1051// //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
1052// if (List != NULL) {
1053// for (LinkedNodes::iterator Runner = List->begin();Runner != List->end();Runner++) {
1054// if (mol->TesselStruct->PointsOnBoundary.find((*Runner)->nr) == mol->TesselStruct->PointsOnBoundary.end()) {
1055// a = *Runner;
1056// i=3;
1057// for (int j=0;j<NDIM;j++)
1058// LCList->n[j] = LCList->N[j];
1059// break;
1060// }
1061// }
1062// }
1063// }
1064// }
1065// *out << Verbose(0) << "Check: IsInnerPoint() returns " << mol->TesselStruct->IsInnerPoint(out, a, LCList)
1066// << "for atom " << a << " (inside)." << endl;
1067
1068
1069 if (freeLC)
1070 delete(LCList);
1071 *out << Verbose(0) << "End of Find_non_convex_border\n";
1072};
1073
1074/** Finds a hole of sufficient size in \a this molecule to embed \a *srcmol into it.
1075 * \param *out output stream for debugging
1076 * \param *srcmol molecule to embed into
1077 * \return *Vector new center of \a *srcmol for embedding relative to \a this
1078 */
1079Vector* molecule::FindEmbeddingHole(ofstream *out, molecule *srcmol)
1080{
1081 Vector *Center = new Vector;
1082 Center->Zero();
1083 // calculate volume/shape of \a *srcmol
1084
1085 // find embedding holes
1086
1087 // if more than one, let user choose
1088
1089 // return embedding center
1090 return Center;
1091};
1092
Note: See TracBrowser for help on using the repository browser.