source: src/boundary.cpp@ 357fba

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

Huge refactoring of Tesselation routines, but not finished yet.

  • new file tesselation.cpp with all of classes tesselation, Boundary..Set and CandidatesForTesselationOB
  • new file tesselationhelper.cpp with all auxiliary functions.
  • boundary.cpp just contains super functions, combininb molecule and Tesselation pointers
  • new pointer molecule::TesselStruct
  • PointMap, LineMap, TriangleMap DistanceMap have been moved from molecules.hpp to tesselation.hpp
  • new abstract class PointCloud and TesselPoint
  • atom inherits TesselPoint
  • molecule inherits PointCloud (i.e. a set of TesselPoints) and implements all virtual functions for the chained list
  • TriangleFilesWritten is thrown out, intermediate steps are written in find_nonconvex_border and not in find_next_triangle()
  • LinkedCell class uses TesselPoint as its nodes, i.e. as long as any class inherits TesselPoint, it may make use of LinkedCell as well and a PointCloud is used to initialize
  • class atom and bond definitions have been moved to own header files

NOTE: This is not bugfree yet. Tesselation of heptan produces way too many triangles, but runs without faults or leaks.

  • Property mode set to 100755
File size: 44.3 KB
Line 
1#include "boundary.hpp"
2
3#include<gsl/gsl_poly.h>
4
5// ========================================== F U N C T I O N S =================================
6
7
8/** Determines greatest diameters of a cluster defined by its convex envelope.
9 * Looks at lines parallel to one axis and where they intersect on the projected planes
10 * \param *out output stream for debugging
11 * \param *BoundaryPoints NDIM set of boundary points defining the convex envelope on each projected plane
12 * \param *mol molecule structure representing the cluster
13 * \param IsAngstroem whether we have angstroem or atomic units
14 * \return NDIM array of the diameters
15 */
16double *
17GetDiametersOfCluster(ofstream *out, Boundaries *BoundaryPtr, molecule *mol,
18 bool IsAngstroem)
19{
20 // get points on boundary of NULL was given as parameter
21 bool BoundaryFreeFlag = false;
22 Boundaries *BoundaryPoints = BoundaryPtr;
23 if (BoundaryPoints == NULL) {
24 BoundaryFreeFlag = true;
25 BoundaryPoints = GetBoundaryPoints(out, mol);
26 } else {
27 *out << Verbose(1) << "Using given boundary points set." << endl;
28 }
29 // determine biggest "diameter" of cluster for each axis
30 Boundaries::iterator Neighbour, OtherNeighbour;
31 double *GreatestDiameter = new double[NDIM];
32 for (int i = 0; i < NDIM; i++)
33 GreatestDiameter[i] = 0.;
34 double OldComponent, tmp, w1, w2;
35 Vector DistanceVector, OtherVector;
36 int component, Othercomponent;
37 for (int axis = 0; axis < NDIM; axis++)
38 { // regard each projected plane
39 //*out << Verbose(1) << "Current axis is " << axis << "." << endl;
40 for (int j = 0; j < 2; j++)
41 { // and for both axis on the current plane
42 component = (axis + j + 1) % NDIM;
43 Othercomponent = (axis + 1 + ((j + 1) & 1)) % NDIM;
44 //*out << Verbose(1) << "Current component is " << component << ", Othercomponent is " << Othercomponent << "." << endl;
45 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner
46 != BoundaryPoints[axis].end(); runner++)
47 {
48 //*out << Verbose(2) << "Current runner is " << *(runner->second.second) << "." << endl;
49 // seek for the neighbours pair where the Othercomponent sign flips
50 Neighbour = runner;
51 Neighbour++;
52 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
53 Neighbour = BoundaryPoints[axis].begin();
54 DistanceVector.CopyVector(&runner->second.second->x);
55 DistanceVector.SubtractVector(&Neighbour->second.second->x);
56 do
57 { // seek for neighbour pair where it flips
58 OldComponent = DistanceVector.x[Othercomponent];
59 Neighbour++;
60 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
61 Neighbour = BoundaryPoints[axis].begin();
62 DistanceVector.CopyVector(&runner->second.second->x);
63 DistanceVector.SubtractVector(&Neighbour->second.second->x);
64 //*out << Verbose(3) << "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << "." << endl;
65 }
66 while ((runner != Neighbour) && (fabs(OldComponent / fabs(
67 OldComponent) - DistanceVector.x[Othercomponent] / fabs(
68 DistanceVector.x[Othercomponent])) < MYEPSILON)); // as long as sign does not flip
69 if (runner != Neighbour)
70 {
71 OtherNeighbour = Neighbour;
72 if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around
73 OtherNeighbour = BoundaryPoints[axis].end();
74 OtherNeighbour--;
75 //*out << Verbose(2) << "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << "." << endl;
76 // now we have found the pair: Neighbour and OtherNeighbour
77 OtherVector.CopyVector(&runner->second.second->x);
78 OtherVector.SubtractVector(&OtherNeighbour->second.second->x);
79 //*out << Verbose(2) << "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << "." << endl;
80 //*out << Verbose(2) << "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << "." << endl;
81 // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour
82 w1 = fabs(OtherVector.x[Othercomponent]);
83 w2 = fabs(DistanceVector.x[Othercomponent]);
84 tmp = fabs((w1 * DistanceVector.x[component] + w2
85 * OtherVector.x[component]) / (w1 + w2));
86 // mark if it has greater diameter
87 //*out << Verbose(2) << "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << "." << endl;
88 GreatestDiameter[component] = (GreatestDiameter[component]
89 > tmp) ? GreatestDiameter[component] : tmp;
90 } //else
91 //*out << Verbose(2) << "Saw no sign flip, probably top or bottom node." << endl;
92 }
93 }
94 }
95 *out << Verbose(0) << "RESULT: The biggest diameters are "
96 << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and "
97 << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom"
98 : "atomiclength") << "." << endl;
99
100 // free reference lists
101 if (BoundaryFreeFlag)
102 delete[] (BoundaryPoints);
103
104 return GreatestDiameter;
105}
106;
107
108/** Creates the objects in a VRML file.
109 * \param *out output stream for debugging
110 * \param *vrmlfile output stream for tecplot data
111 * \param *Tess Tesselation structure with constructed triangles
112 * \param *mol molecule structure with atom positions
113 */
114void write_vrml_file(ofstream *out, ofstream *vrmlfile, class Tesselation *Tess, class molecule *mol)
115{
116 atom *Walker = mol->start;
117 bond *Binder = mol->first;
118 int i;
119 Vector *center = mol->DetermineCenterOfAll(out);
120 if (vrmlfile != NULL) {
121 //cout << Verbose(1) << "Writing Raster3D file ... ";
122 *vrmlfile << "#VRML V2.0 utf8" << endl;
123 *vrmlfile << "#Created by molecuilder" << endl;
124 *vrmlfile << "#All atoms as spheres" << endl;
125 while (Walker->next != mol->end) {
126 Walker = Walker->next;
127 *vrmlfile << "Sphere {" << endl << " "; // 2 is sphere type
128 for (i=0;i<NDIM;i++)
129 *vrmlfile << Walker->x.x[i]-center->x[i] << " ";
130 *vrmlfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
131 }
132
133 *vrmlfile << "# All bonds as vertices" << endl;
134 while (Binder->next != mol->last) {
135 Binder = Binder->next;
136 *vrmlfile << "3" << endl << " "; // 2 is round-ended cylinder type
137 for (i=0;i<NDIM;i++)
138 *vrmlfile << Binder->leftatom->x.x[i]-center->x[i] << " ";
139 *vrmlfile << "\t0.03\t";
140 for (i=0;i<NDIM;i++)
141 *vrmlfile << Binder->rightatom->x.x[i]-center->x[i] << " ";
142 *vrmlfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour
143 }
144
145 *vrmlfile << "# All tesselation triangles" << endl;
146 for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) {
147 *vrmlfile << "1" << endl << " "; // 1 is triangle type
148 for (i=0;i<3;i++) { // print each node
149 for (int j=0;j<NDIM;j++) // and for each node all NDIM coordinates
150 *vrmlfile << TriangleRunner->second->endpoints[i]->node->node->x[j]-center->x[j] << " ";
151 *vrmlfile << "\t";
152 }
153 *vrmlfile << "1. 0. 0." << endl; // red as colour
154 *vrmlfile << "18" << endl << " 0.5 0.5 0.5" << endl; // 18 is transparency type for previous object
155 }
156 } else {
157 cerr << "ERROR: Given vrmlfile is " << vrmlfile << "." << endl;
158 }
159 delete(center);
160};
161
162/** Creates the objects in a raster3d file (renderable with a header.r3d).
163 * \param *out output stream for debugging
164 * \param *rasterfile output stream for tecplot data
165 * \param *Tess Tesselation structure with constructed triangles
166 * \param *mol molecule structure with atom positions
167 */
168void write_raster3d_file(ofstream *out, ofstream *rasterfile, class Tesselation *Tess, class molecule *mol)
169{
170 atom *Walker = mol->start;
171 bond *Binder = mol->first;
172 int i;
173 Vector *center = mol->DetermineCenterOfAll(out);
174 if (rasterfile != NULL) {
175 //cout << Verbose(1) << "Writing Raster3D file ... ";
176 *rasterfile << "# Raster3D object description, created by MoleCuilder" << endl;
177 *rasterfile << "@header.r3d" << endl;
178 *rasterfile << "# All atoms as spheres" << endl;
179 while (Walker->next != mol->end) {
180 Walker = Walker->next;
181 *rasterfile << "2" << endl << " "; // 2 is sphere type
182 for (i=0;i<NDIM;i++)
183 *rasterfile << Walker->x.x[i]-center->x[i] << " ";
184 *rasterfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
185 }
186
187 *rasterfile << "# All bonds as vertices" << endl;
188 while (Binder->next != mol->last) {
189 Binder = Binder->next;
190 *rasterfile << "3" << endl << " "; // 2 is round-ended cylinder type
191 for (i=0;i<NDIM;i++)
192 *rasterfile << Binder->leftatom->x.x[i]-center->x[i] << " ";
193 *rasterfile << "\t0.03\t";
194 for (i=0;i<NDIM;i++)
195 *rasterfile << Binder->rightatom->x.x[i]-center->x[i] << " ";
196 *rasterfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour
197 }
198
199 *rasterfile << "# All tesselation triangles" << endl;
200 *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";
201 for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) {
202 *rasterfile << "1" << endl << " "; // 1 is triangle type
203 for (i=0;i<3;i++) { // print each node
204 for (int j=0;j<NDIM;j++) // and for each node all NDIM coordinates
205 *rasterfile << TriangleRunner->second->endpoints[i]->node->node->x[j]-center->x[j] << " ";
206 *rasterfile << "\t";
207 }
208 *rasterfile << "1. 0. 0." << endl; // red as colour
209 //*rasterfile << "18" << endl << " 0.5 0.5 0.5" << endl; // 18 is transparency type for previous object
210 }
211 *rasterfile << "9\n terminating special property\n";
212 } else {
213 cerr << "ERROR: Given rasterfile is " << rasterfile << "." << endl;
214 }
215 delete(center);
216};
217
218/** This function creates the tecplot file, displaying the tesselation of the hull.
219 * \param *out output stream for debugging
220 * \param *tecplot output stream for tecplot data
221 * \param N arbitrary number to differentiate various zones in the tecplot format
222 */
223void write_tecplot_file(ofstream *out, ofstream *tecplot, class Tesselation *TesselStruct, class molecule *mol, int N)
224{
225 if (tecplot != NULL) {
226 *tecplot << "TITLE = \"3D CONVEX SHELL\"" << endl;
227 *tecplot << "VARIABLES = \"X\" \"Y\" \"Z\"" << endl;
228 *tecplot << "ZONE T=\"TRIANGLES" << N << "\", N=" << TesselStruct->PointsOnBoundaryCount << ", E=" << TesselStruct->TrianglesOnBoundaryCount << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl;
229 int *LookupList = new int[mol->AtomCount];
230 for (int i = 0; i < mol->AtomCount; i++)
231 LookupList[i] = -1;
232
233 // print atom coordinates
234 *out << Verbose(2) << "The following triangles were created:";
235 int Counter = 1;
236 TesselPoint *Walker = NULL;
237 for (PointMap::iterator target = TesselStruct->PointsOnBoundary.begin(); target != TesselStruct->PointsOnBoundary.end(); target++) {
238 Walker = target->second->node;
239 LookupList[Walker->nr] = Counter++;
240 *tecplot << Walker->node->x[0] << " " << Walker->node->x[1] << " " << Walker->node->x[2] << " " << endl;
241 }
242 *tecplot << endl;
243 // print connectivity
244 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++) {
245 *out << " " << runner->second->endpoints[0]->node->Name << "<->" << runner->second->endpoints[1]->node->Name << "<->" << runner->second->endpoints[2]->node->Name;
246 *tecplot << LookupList[runner->second->endpoints[0]->node->nr] << " " << LookupList[runner->second->endpoints[1]->node->nr] << " " << LookupList[runner->second->endpoints[2]->node->nr] << endl;
247 }
248 delete[] (LookupList);
249 *out << endl;
250 }
251}
252
253
254/** Determines the boundary points of a cluster.
255 * Does a projection per axis onto the orthogonal plane, transforms into spherical coordinates, sorts them by the angle
256 * and looks at triples: if the middle has less a distance than the allowed maximum height of the triangle formed by the plane's
257 * center and first and last point in the triple, it is thrown out.
258 * \param *out output stream for debugging
259 * \param *mol molecule structure representing the cluster
260 */
261Boundaries *GetBoundaryPoints(ofstream *out, molecule *mol)
262{
263 atom *Walker = NULL;
264 PointMap PointsOnBoundary;
265 LineMap LinesOnBoundary;
266 TriangleMap TrianglesOnBoundary;
267 Vector *MolCenter = mol->DetermineCenterOfAll(out);
268 Vector helper;
269
270 *out << Verbose(1) << "Finding all boundary points." << endl;
271 Boundaries *BoundaryPoints = new Boundaries[NDIM]; // first is alpha, second is (r, nr)
272 BoundariesTestPair BoundaryTestPair;
273 Vector AxisVector, AngleReferenceVector, AngleReferenceNormalVector;
274 double radius, angle;
275 // 3a. Go through every axis
276 for (int axis = 0; axis < NDIM; axis++) {
277 AxisVector.Zero();
278 AngleReferenceVector.Zero();
279 AngleReferenceNormalVector.Zero();
280 AxisVector.x[axis] = 1.;
281 AngleReferenceVector.x[(axis + 1) % NDIM] = 1.;
282 AngleReferenceNormalVector.x[(axis + 2) % NDIM] = 1.;
283
284 *out << Verbose(1) << "Axisvector is " << AxisVector << " and AngleReferenceVector is " << AngleReferenceVector << ", and AngleReferenceNormalVector is " << AngleReferenceNormalVector << "." << endl;
285
286 // 3b. construct set of all points, transformed into cylindrical system and with left and right neighbours
287 Walker = mol->start;
288 while (Walker->next != mol->end) {
289 Walker = Walker->next;
290 Vector ProjectedVector;
291 ProjectedVector.CopyVector(&Walker->x);
292 ProjectedVector.SubtractVector(MolCenter);
293 ProjectedVector.ProjectOntoPlane(&AxisVector);
294
295 // correct for negative side
296 radius = ProjectedVector.NormSquared();
297 if (fabs(radius) > MYEPSILON)
298 angle = ProjectedVector.Angle(&AngleReferenceVector);
299 else
300 angle = 0.; // otherwise it's a vector in Axis Direction and unimportant for boundary issues
301
302 //*out << "Checking sign in quadrant : " << ProjectedVector.Projection(&AngleReferenceNormalVector) << "." << endl;
303 if (ProjectedVector.Projection(&AngleReferenceNormalVector) > 0) {
304 angle = 2. * M_PI - angle;
305 }
306 *out << Verbose(2) << "Inserting " << *Walker << ": (r, alpha) = (" << radius << "," << angle << "): " << ProjectedVector << endl;
307 BoundaryTestPair = BoundaryPoints[axis].insert(BoundariesPair(angle, DistancePair (radius, Walker)));
308 if (!BoundaryTestPair.second) { // same point exists, check first r, then distance of original vectors to center of gravity
309 *out << Verbose(2) << "Encountered two vectors whose projection onto axis " << axis << " is equal: " << endl;
310 *out << Verbose(2) << "Present vector: " << *BoundaryTestPair.first->second.second << endl;
311 *out << Verbose(2) << "New vector: " << *Walker << endl;
312 double tmp = ProjectedVector.NormSquared();
313 if ((tmp - BoundaryTestPair.first->second.first) > MYEPSILON) {
314 BoundaryTestPair.first->second.first = tmp;
315 BoundaryTestPair.first->second.second = Walker;
316 *out << Verbose(2) << "Keeping new vector due to larger projected distance " << tmp << "." << endl;
317 } else if (fabs(tmp - BoundaryTestPair.first->second.first) < MYEPSILON) {
318 helper.CopyVector(&Walker->x);
319 helper.SubtractVector(MolCenter);
320 tmp = helper.NormSquared();
321 helper.CopyVector(&BoundaryTestPair.first->second.second->x);
322 helper.SubtractVector(MolCenter);
323 if (helper.NormSquared() < tmp) {
324 BoundaryTestPair.first->second.second = Walker;
325 *out << Verbose(2) << "Keeping new vector due to larger distance to molecule center " << helper.NormSquared() << "." << endl;
326 } else {
327 *out << Verbose(2) << "Keeping present vector due to larger distance to molecule center " << tmp << "." << endl;
328 }
329 } else {
330 *out << Verbose(2) << "Keeping present vector due to larger projected distance " << tmp << "." << endl;
331 }
332 }
333 }
334 // printing all inserted for debugging
335 // {
336 // *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
337 // int i=0;
338 // for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
339 // if (runner != BoundaryPoints[axis].begin())
340 // *out << ", " << i << ": " << *runner->second.second;
341 // else
342 // *out << i << ": " << *runner->second.second;
343 // i++;
344 // }
345 // *out << endl;
346 // }
347 // 3c. throw out points whose distance is less than the mean of left and right neighbours
348 bool flag = false;
349 *out << Verbose(1) << "Looking for candidates to kick out by convex condition ... " << endl;
350 do { // do as long as we still throw one out per round
351 flag = false;
352 Boundaries::iterator left = BoundaryPoints[axis].end();
353 Boundaries::iterator right = BoundaryPoints[axis].end();
354 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
355 // set neighbours correctly
356 if (runner == BoundaryPoints[axis].begin()) {
357 left = BoundaryPoints[axis].end();
358 } else {
359 left = runner;
360 }
361 left--;
362 right = runner;
363 right++;
364 if (right == BoundaryPoints[axis].end()) {
365 right = BoundaryPoints[axis].begin();
366 }
367 // check distance
368
369 // construct the vector of each side of the triangle on the projected plane (defined by normal vector AxisVector)
370 {
371 Vector SideA, SideB, SideC, SideH;
372 SideA.CopyVector(&left->second.second->x);
373 SideA.SubtractVector(MolCenter);
374 SideA.ProjectOntoPlane(&AxisVector);
375 // *out << "SideA: ";
376 // SideA.Output(out);
377 // *out << endl;
378
379 SideB.CopyVector(&right->second.second->x);
380 SideB.SubtractVector(MolCenter);
381 SideB.ProjectOntoPlane(&AxisVector);
382 // *out << "SideB: ";
383 // SideB.Output(out);
384 // *out << endl;
385
386 SideC.CopyVector(&left->second.second->x);
387 SideC.SubtractVector(&right->second.second->x);
388 SideC.ProjectOntoPlane(&AxisVector);
389 // *out << "SideC: ";
390 // SideC.Output(out);
391 // *out << endl;
392
393 SideH.CopyVector(&runner->second.second->x);
394 SideH.SubtractVector(MolCenter);
395 SideH.ProjectOntoPlane(&AxisVector);
396 // *out << "SideH: ";
397 // SideH.Output(out);
398 // *out << endl;
399
400 // calculate each length
401 double a = SideA.Norm();
402 //double b = SideB.Norm();
403 //double c = SideC.Norm();
404 double h = SideH.Norm();
405 // calculate the angles
406 double alpha = SideA.Angle(&SideH);
407 double beta = SideA.Angle(&SideC);
408 double gamma = SideB.Angle(&SideH);
409 double delta = SideC.Angle(&SideH);
410 double MinDistance = a * sin(beta) / (sin(delta)) * (((alpha < M_PI / 2.) || (gamma < M_PI / 2.)) ? 1. : -1.);
411 //*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;
412 *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;
413 if ((fabs(h / fabs(h) - MinDistance / fabs(MinDistance)) < MYEPSILON) && ((h - MinDistance)) < -MYEPSILON) {
414 // throw out point
415 *out << Verbose(1) << "Throwing out " << *runner->second.second << "." << endl;
416 BoundaryPoints[axis].erase(runner);
417 flag = true;
418 }
419 }
420 }
421 } while (flag);
422 }
423 delete(MolCenter);
424 return BoundaryPoints;
425};
426
427/** Tesselates the convex boundary by finding all boundary points.
428 * \param *out output stream for debugging
429 * \param *mol molecule structure with Atom's and Bond's
430 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
431 * \param *LCList atoms in LinkedCell list
432 * \param *filename filename prefix for output of vertex data
433 * \return *TesselStruct is filled with convex boundary and tesselation is stored under \a *filename.
434 */
435void Find_convex_border(ofstream *out, molecule* mol, class Tesselation *&TesselStruct, class LinkedCell *LCList, const char *filename)
436{
437 bool BoundaryFreeFlag = false;
438 Boundaries *BoundaryPoints = NULL;
439
440 cout << Verbose(1) << "Begin of find_convex_border" << endl;
441
442 if (TesselStruct != NULL) // free if allocated
443 delete(TesselStruct);
444 TesselStruct = new class Tesselation;
445
446 // 1. Find all points on the boundary
447 if (BoundaryPoints == NULL) {
448 BoundaryFreeFlag = true;
449 BoundaryPoints = GetBoundaryPoints(out, mol);
450 } else {
451 *out << Verbose(1) << "Using given boundary points set." << endl;
452 }
453
454// printing all inserted for debugging
455 for (int axis=0; axis < NDIM; axis++)
456 {
457 *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
458 int i=0;
459 for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
460 if (runner != BoundaryPoints[axis].begin())
461 *out << ", " << i << ": " << *runner->second.second;
462 else
463 *out << i << ": " << *runner->second.second;
464 i++;
465 }
466 *out << endl;
467 }
468
469 // 2. fill the boundary point list
470 for (int axis = 0; axis < NDIM; axis++)
471 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++)
472 TesselStruct->AddPoint(runner->second.second);
473
474 *out << Verbose(2) << "I found " << TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl;
475 // now we have the whole set of edge points in the BoundaryList
476
477 // listing for debugging
478 // *out << Verbose(1) << "Listing PointsOnBoundary:";
479 // for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
480 // *out << " " << *runner->second;
481 // }
482 // *out << endl;
483
484 // 3a. guess starting triangle
485 TesselStruct->GuessStartingTriangle(out);
486
487 // 3b. go through all lines, that are not yet part of two triangles (only of one so far)
488 TesselStruct->TesselateOnBoundary(out, mol);
489
490 // 3c. check whether all atoms lay inside the boundary, if not, add to boundary points, segment triangle into three with the new point
491 if (!TesselStruct->InsertStraddlingPoints(out, mol))
492 *out << Verbose(1) << "Insertion of straddling points failed!" << endl;
493
494 // 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
495 if (!TesselStruct->CorrectConcaveBaselines(out))
496 *out << Verbose(1) << "Correction of concave baselines failed!" << endl;
497
498 *out << Verbose(2) << "I created " << TesselStruct->TrianglesOnBoundary.size() << " triangles with " << TesselStruct->LinesOnBoundary.size() << " lines and " << TesselStruct->PointsOnBoundary.size() << " points." << endl;
499
500 // 4. Store triangles in tecplot file
501 if (filename != NULL) {
502 if (DoTecplotOutput) {
503 string OutputName(filename);
504 OutputName.append(TecplotSuffix);
505 ofstream *tecplot = new ofstream(OutputName.c_str());
506 write_tecplot_file(out, tecplot, TesselStruct, mol, 0);
507 tecplot->close();
508 delete(tecplot);
509 }
510 if (DoRaster3DOutput) {
511 string OutputName(filename);
512 OutputName.append(Raster3DSuffix);
513 ofstream *rasterplot = new ofstream(OutputName.c_str());
514 write_raster3d_file(out, rasterplot, TesselStruct, mol);
515 rasterplot->close();
516 delete(rasterplot);
517 }
518 }
519
520 // free reference lists
521 if (BoundaryFreeFlag)
522 delete[] (BoundaryPoints);
523
524 cout << Verbose(1) << "End of find_convex_border" << endl;
525};
526
527
528/** Determines the volume of a cluster.
529 * Determines first the convex envelope, then tesselates it and calculates its volume.
530 * \param *out output stream for debugging
531 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
532 * \param *configuration needed for path to store convex envelope file
533 * \return determined volume of the cluster in cubed config:GetIsAngstroem()
534 */
535double VolumeOfConvexEnvelope(ofstream *out, class Tesselation *TesselStruct, class config *configuration)
536{
537 bool IsAngstroem = configuration->GetIsAngstroem();
538 double volume = 0.;
539 double PyramidVolume = 0.;
540 double G, h;
541 Vector x, y;
542 double a, b, c;
543
544 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
545 *out << Verbose(1)
546 << "Calculating the volume of the pyramids formed out of triangles and center of gravity."
547 << endl;
548 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++)
549 { // go through every triangle, calculate volume of its pyramid with CoG as peak
550 x.CopyVector(runner->second->endpoints[0]->node->node);
551 x.SubtractVector(runner->second->endpoints[1]->node->node);
552 y.CopyVector(runner->second->endpoints[0]->node->node);
553 y.SubtractVector(runner->second->endpoints[2]->node->node);
554 a = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
555 b = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[2]->node->node));
556 c = sqrt(runner->second->endpoints[2]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
557 G = sqrt(((a + b + c) * (a + b + c) - 2 * (a * a + b * b + c * c)) / 16.); // area of tesselated triangle
558 x.MakeNormalVector(runner->second->endpoints[0]->node->node, runner->second->endpoints[1]->node->node, runner->second->endpoints[2]->node->node);
559 x.Scale(runner->second->endpoints[1]->node->node->Projection(&x));
560 h = x.Norm(); // distance of CoG to triangle
561 PyramidVolume = (1. / 3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
562 *out << Verbose(2) << "Area of triangle is " << G << " "
563 << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is "
564 << h << " and the volume is " << PyramidVolume << " "
565 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
566 volume += PyramidVolume;
567 }
568 *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10)
569 << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3."
570 << endl;
571
572 return volume;
573}
574;
575
576/** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
577 * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
578 * \param *out output stream for debugging
579 * \param *configuration needed for path to store convex envelope file
580 * \param *mol molecule structure representing the cluster
581 * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead.
582 * \param celldensity desired average density in final cell
583 */
584void
585PrepareClustersinWater(ofstream *out, config *configuration, molecule *mol,
586 double ClusterVolume, double celldensity)
587{
588 // transform to PAS
589 mol->PrincipalAxisSystem(out, true);
590
591 // some preparations beforehand
592 bool IsAngstroem = configuration->GetIsAngstroem();
593 Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol);
594 class Tesselation *TesselStruct = NULL;
595 LinkedCell LCList(mol, 10.);
596 Find_convex_border(out, mol, TesselStruct, &LCList, NULL);
597 double clustervolume;
598 if (ClusterVolume == 0)
599 clustervolume = VolumeOfConvexEnvelope(out, TesselStruct, configuration);
600 else
601 clustervolume = ClusterVolume;
602 double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, IsAngstroem);
603 Vector BoxLengths;
604 int repetition[NDIM] =
605 { 1, 1, 1 };
606 int TotalNoClusters = 1;
607 for (int i = 0; i < NDIM; i++)
608 TotalNoClusters *= repetition[i];
609
610 // sum up the atomic masses
611 double totalmass = 0.;
612 atom *Walker = mol->start;
613 while (Walker->next != mol->end)
614 {
615 Walker = Walker->next;
616 totalmass += Walker->type->mass;
617 }
618 *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10)
619 << totalmass << " atomicmassunit." << endl;
620
621 *out << Verbose(0) << "RESULT: The average density is " << setprecision(10)
622 << totalmass / clustervolume << " atomicmassunit/"
623 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
624
625 // solve cubic polynomial
626 *out << Verbose(1) << "Solving equidistant suspension in water problem ..."
627 << endl;
628 double cellvolume;
629 if (IsAngstroem)
630 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_A - (totalmass
631 / clustervolume)) / (celldensity - 1);
632 else
633 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_a0 - (totalmass
634 / clustervolume)) / (celldensity - 1);
635 *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity
636 << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom"
637 : "atomiclength") << "^3." << endl;
638
639 double minimumvolume = TotalNoClusters * (GreatestDiameter[0]
640 * GreatestDiameter[1] * GreatestDiameter[2]);
641 *out << Verbose(1)
642 << "Minimum volume of the convex envelope contained in a rectangular box is "
643 << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom"
644 : "atomiclength") << "^3." << endl;
645 if (minimumvolume > cellvolume)
646 {
647 cerr << Verbose(0)
648 << "ERROR: the containing box already has a greater volume than the envisaged cell volume!"
649 << endl;
650 cout << Verbose(0)
651 << "Setting Box dimensions to minimum possible, the greatest diameters."
652 << endl;
653 for (int i = 0; i < NDIM; i++)
654 BoxLengths.x[i] = GreatestDiameter[i];
655 mol->CenterEdge(out, &BoxLengths);
656 }
657 else
658 {
659 BoxLengths.x[0] = (repetition[0] * GreatestDiameter[0] + repetition[1]
660 * GreatestDiameter[1] + repetition[2] * GreatestDiameter[2]);
661 BoxLengths.x[1] = (repetition[0] * repetition[1] * GreatestDiameter[0]
662 * GreatestDiameter[1] + repetition[0] * repetition[2]
663 * GreatestDiameter[0] * GreatestDiameter[2] + repetition[1]
664 * repetition[2] * GreatestDiameter[1] * GreatestDiameter[2]);
665 BoxLengths.x[2] = minimumvolume - cellvolume;
666 double x0 = 0., x1 = 0., x2 = 0.;
667 if (gsl_poly_solve_cubic(BoxLengths.x[0], BoxLengths.x[1],
668 BoxLengths.x[2], &x0, &x1, &x2) == 1) // either 1 or 3 on return
669 *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0
670 << " ." << endl;
671 else
672 {
673 *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0
674 << " and " << x1 << " and " << x2 << " ." << endl;
675 x0 = x2; // sorted in ascending order
676 }
677
678 cellvolume = 1;
679 for (int i = 0; i < NDIM; i++)
680 {
681 BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]);
682 cellvolume *= BoxLengths.x[i];
683 }
684
685 // set new box dimensions
686 *out << Verbose(0) << "Translating to box with these boundaries." << endl;
687 mol->SetBoxDimension(&BoxLengths);
688 mol->CenterInBox((ofstream *) &cout);
689 }
690 // update Box of atoms by boundary
691 mol->SetBoxDimension(&BoxLengths);
692 *out << Verbose(0) << "RESULT: The resulting cell dimensions are: "
693 << BoxLengths.x[0] << " and " << BoxLengths.x[1] << " and "
694 << BoxLengths.x[2] << " with total volume of " << cellvolume << " "
695 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
696}
697;
698
699
700/** Fills the empty space of the simulation box with water/
701 * \param *out output stream for debugging
702 * \param *List list of molecules already present in box
703 * \param *TesselStruct contains tesselated surface
704 * \param *filler molecule which the box is to be filled with
705 * \param configuration contains box dimensions
706 * \param distance[NDIM] distance between filling molecules in each direction
707 * \param RandAtomDisplacement maximum distance for random displacement per atom
708 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
709 * \param DoRandomRotation true - do random rotiations, false - don't
710 * \return *mol pointer to new molecule with filled atoms
711 */
712molecule * FillBoxWithMolecule(ofstream *out, MoleculeListClass *List, molecule *filler, config &configuration, double distance[NDIM], double RandomAtomDisplacement, double RandomMolDisplacement, bool DoRandomRotation)
713{
714 molecule *Filling = new molecule(filler->elemente);
715 Vector CurrentPosition;
716 int N[NDIM];
717 int n[NDIM];
718 double *M = filler->ReturnFullMatrixforSymmetric(filler->cell_size);
719 double Rotations[NDIM*NDIM];
720 Vector AtomTranslations;
721 Vector FillerTranslations;
722 Vector FillerDistance;
723 double FillIt = false;
724 atom *Walker = NULL, *Runner = NULL;
725 bond *Binder = NULL;
726
727 // Center filler at origin
728 filler->CenterOrigin(out);
729 filler->Center.Zero();
730
731 // calculate filler grid in [0,1]^3
732 FillerDistance.Init(distance[0], distance[1], distance[2]);
733 FillerDistance.InverseMatrixMultiplication(M);
734 for(int i=0;i<NDIM;i++)
735 N[i] = ceil(1./FillerDistance.x[i]);
736
737 // go over [0,1]^3 filler grid
738 for (n[0] = 0; n[0] < N[0]; n[0]++)
739 for (n[1] = 0; n[1] < N[1]; n[1]++)
740 for (n[2] = 0; n[2] < N[2]; n[2]++) {
741 // calculate position of current grid vector in untransformed box
742 CurrentPosition.Init(n[0], n[1], n[2]);
743 CurrentPosition.MatrixMultiplication(M);
744 // Check whether point is in- or outside
745 FillIt = true;
746 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
747 FillIt = FillIt && (!(*ListRunner)->TesselStruct->IsInside(&CurrentPosition));
748 }
749
750 if (FillIt) {
751 // fill in Filler
752 *out << Verbose(2) << "Space at " << CurrentPosition << " is unoccupied by any molecule, filling in." << endl;
753
754 // create molecule random translation vector ...
755 for (int i=0;i<NDIM;i++)
756 FillerTranslations.x[i] = RandomMolDisplacement*(rand()/(RAND_MAX/2.) - 1.);
757
758 // go through all atoms
759 Walker = filler->start;
760 while (Walker != filler->end) {
761 Walker = Walker->next;
762 // copy atom ...
763 *Runner = new atom(Walker);
764
765 // create atomic random translation vector ...
766 for (int i=0;i<NDIM;i++)
767 AtomTranslations.x[i] = RandomAtomDisplacement*(rand()/(RAND_MAX/2.) - 1.);
768
769 // ... and rotation matrix
770 if (DoRandomRotation) {
771 double phi[NDIM];
772 for (int i=0;i<NDIM;i++) {
773 phi[i] = rand()/(RAND_MAX/(2.*M_PI));
774 }
775
776 Rotations[0] = cos(phi[0]) *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2]));
777 Rotations[3] = sin(phi[0]) *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2]));
778 Rotations[6] = cos(phi[1])*sin(phi[2]) ;
779 Rotations[1] = - sin(phi[0])*cos(phi[1]) ;
780 Rotations[4] = cos(phi[0])*cos(phi[1]) ;
781 Rotations[7] = sin(phi[1]) ;
782 Rotations[3] = - cos(phi[0]) *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2]));
783 Rotations[5] = - sin(phi[0]) *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2]));
784 Rotations[8] = cos(phi[1])*cos(phi[2]) ;
785 }
786
787 // ... and put at new position
788 if (DoRandomRotation)
789 Runner->x.MatrixMultiplication(Rotations);
790 Runner->x.AddVector(&AtomTranslations);
791 Runner->x.AddVector(&FillerTranslations);
792 Runner->x.AddVector(&CurrentPosition);
793 // insert into Filling
794 Filling->AddAtom(Runner);
795 }
796
797 // go through all bonds and add as well
798 Binder = filler->first;
799 while(Binder != filler->last) {
800 Binder = Binder->next;
801 }
802 } else {
803 // leave empty
804 *out << Verbose(2) << "Space at " << CurrentPosition << " is occupied." << endl;
805 }
806 }
807 return Filling;
808};
809
810/** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
811 * \param *out output stream for debugging
812 * \param *mol molecule structure with Atom's and Bond's
813 * \param *Tess Tesselation filled with points, lines and triangles on boundary on return
814 * \param *LCList atoms in LinkedCell list
815 * \param *filename filename prefix for output of vertex data
816 * \para RADIUS radius of the virtual sphere
817 */
818void Find_non_convex_border(ofstream *out, molecule* mol, class Tesselation *Tess, class LinkedCell *LCList, const char *filename, const double RADIUS)
819{
820 int N = 0;
821 bool freeTess = false;
822 bool freeLC = false;
823 ofstream *tempstream = NULL;
824 char NumberName[255];
825 int TriangleFilesWritten = 0;
826
827 *out << Verbose(1) << "Entering search for non convex hull. " << endl;
828 if (Tess == NULL) {
829 *out << Verbose(1) << "Allocating Tesselation struct ..." << endl;
830 Tess = new Tesselation;
831 freeTess = true;
832 }
833 LineMap::iterator baseline;
834 LineMap::iterator testline;
835 *out << Verbose(0) << "Begin of Find_non_convex_border\n";
836 bool flag = false; // marks whether we went once through all baselines without finding any without two triangles
837 bool failflag = false;
838
839 if (LCList == NULL) {
840 LCList = new LinkedCell(mol, 2.*RADIUS);
841 freeLC = true;
842 }
843
844 Tess->Find_starting_triangle(out, RADIUS, LCList);
845
846 baseline = Tess->LinesOnBoundary.begin();
847 while ((baseline != Tess->LinesOnBoundary.end()) || (flag)) {
848 if (baseline->second->TrianglesCount == 1) {
849 failflag = Tess->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.
850 flag = flag || failflag;
851 if (!failflag)
852 cerr << "WARNING: Find_next_suitable_triangle failed." << endl;
853 } else {
854 //cout << Verbose(1) << "Line " << *baseline->second << " has " << baseline->second->TrianglesCount << " triangles adjacent" << endl;
855 if (baseline->second->TrianglesCount != 2)
856 cout << Verbose(1) << "ERROR: TESSELATION FINISHED WITH INVALID TRIANGLE COUNT!" << endl;
857 }
858
859 N++;
860 baseline++;
861 if ((baseline == Tess->LinesOnBoundary.end()) && (flag)) {
862 baseline = Tess->LinesOnBoundary.begin(); // restart if we reach end due to newly inserted lines
863 flag = false;
864 }
865
866 // write temporary envelope
867 if ((DoSingleStepOutput && (Tess->TrianglesOnBoundaryCount % 1 == 0))) { // if we have a new triangle and want to output each new triangle configuration
868 class BoundaryTriangleSet *triangle = (Tess->TrianglesOnBoundary.end()--)->second;
869 sprintf(NumberName, "-%04d-%s_%s_%s", TriangleFilesWritten, triangle->endpoints[0]->node->Name, triangle->endpoints[1]->node->Name, triangle->endpoints[2]->node->Name);
870 if (DoTecplotOutput) {
871 string NameofTempFile(filename);
872 NameofTempFile.append(NumberName);
873 for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
874 NameofTempFile.erase(npos, 1);
875 NameofTempFile.append(TecplotSuffix);
876 cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
877 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
878 write_tecplot_file(out, tempstream, Tess, mol, TriangleFilesWritten);
879 tempstream->close();
880 tempstream->flush();
881 delete(tempstream);
882 }
883
884 if (DoRaster3DOutput) {
885 string NameofTempFile(filename);
886 NameofTempFile.append(NumberName);
887 for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
888 NameofTempFile.erase(npos, 1);
889 NameofTempFile.append(Raster3DSuffix);
890 cout << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
891 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
892 write_raster3d_file(out, tempstream, Tess, mol);
893// // include the current position of the virtual sphere in the temporary raster3d file
894// // make the circumsphere's center absolute again
895// helper.CopyVector(BaseRay->endpoints[0]->node->node);
896// helper.AddVector(BaseRay->endpoints[1]->node->node);
897// helper.Scale(0.5);
898// (*it)->OptCenter.AddVector(&helper);
899// Vector *center = mol->DetermineCenterOfAll(out);
900// (*it)->OptCenter.SubtractVector(center);
901// delete(center);
902// // and add to file plus translucency object
903// *tempstream << "# current virtual sphere\n";
904// *tempstream << "8\n 25.0 0.6 -1.0 -1.0 -1.0 0.2 0 0 0 0\n";
905// *tempstream << "2\n " << (*it)->OptCenter.x[0] << " "
906// << (*it)->OptCenter.x[1] << " " << (*it)->OptCenter.x[2]
907// << "\t" << RADIUS << "\t1 0 0\n";
908// *tempstream << "9\n terminating special property\n";
909 tempstream->close();
910 tempstream->flush();
911 delete(tempstream);
912 }
913 if (DoTecplotOutput || DoRaster3DOutput)
914 TriangleFilesWritten++;
915 }
916 }
917
918 // write final envelope
919 if (filename != 0) {
920 *out << Verbose(1) << "Writing final tecplot file\n";
921 if (DoTecplotOutput) {
922 string OutputName(filename);
923 OutputName.append(TecplotSuffix);
924 ofstream *tecplot = new ofstream(OutputName.c_str());
925 write_tecplot_file(out, tecplot, Tess, mol, -1);
926 tecplot->close();
927 delete(tecplot);
928 }
929 if (DoRaster3DOutput) {
930 string OutputName(filename);
931 OutputName.append(Raster3DSuffix);
932 ofstream *raster = new ofstream(OutputName.c_str());
933 write_raster3d_file(out, raster, Tess, mol);
934 raster->close();
935 delete(raster);
936 }
937 } else {
938 cerr << "ERROR: Could definitively not find all necessary triangles!" << endl;
939 }
940
941 cout << Verbose(2) << "Check: List of Baselines with not two connected triangles:" << endl;
942 int counter = 0;
943 for (testline = Tess->LinesOnBoundary.begin(); testline != Tess->LinesOnBoundary.end(); testline++) {
944 if (testline->second->TrianglesCount != 2) {
945 cout << Verbose(2) << *testline->second << "\t" << testline->second->TrianglesCount << endl;
946 counter++;
947 }
948 }
949 if (counter == 0)
950 cout << Verbose(2) << "None." << endl;
951
952 if (freeTess)
953 delete(Tess);
954 if (freeLC)
955 delete(LCList);
956 *out << Verbose(0) << "End of Find_non_convex_border\n";
957};
958
959/** Finds a hole of sufficient size in \a this molecule to embed \a *srcmol into it.
960 * \param *out output stream for debugging
961 * \param *srcmol molecule to embed into
962 * \return *Vector new center of \a *srcmol for embedding relative to \a this
963 */
964Vector* molecule::FindEmbeddingHole(ofstream *out, molecule *srcmol)
965{
966 Vector *Center = new Vector;
967 Center->Zero();
968 // calculate volume/shape of \a *srcmol
969
970 // find embedding holes
971
972 // if more than one, let user choose
973
974 // return embedding center
975 return Center;
976};
977
Note: See TracBrowser for help on using the repository browser.