source: src/boundary.cpp@ 86381b

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 86381b was 08ef35, checked in by Frederik Heber <heber@…>, 16 years ago

New function ConvexizeNonconvexEnvelope() to calculate the volume of a non-convex envelope.

The central idea is that the volume of a convex envelope is easy to determine as a sum of pyramids with respect to a center inside the envelope. Hence, if we can "reduce" the non-convex envelope to a convex one in such a way that we know the added volume, we may determine the volume of a non-convex envelope.
The nice side effect is that we may use our Find_non_convex_border() algorithm to calculate also the convex envelope.

  • We go through all BoundaryPoints and check whether one of its Baselines does not fulfill the ConvexCriterion. If so, we remove it, as it can not be a boundary point on the convex envelope, and re-construct the attached triangles. The added volume is a general tetraeder, whose formula is known.
  • FIX: Find_convex_border() - We check whether AddPoint is successful or not.
  • builder.cpp: case 'o' - changed to use ConvexizeNonconvexEnvelope() instead of Find_convex_border()
  • Tesselation:AddPoint() - now takes second argument which is the index for BPS and always set BPS to either the newly created or the already present point. Return argument discerns between new and already present point.
  • Tesselation::BPS, BLS, BTS are now public not private. We have to access them from ConvexizeNonconvexEnvelope()
  • Property mode set to 100755
File size: 56.2 KB
Line 
1/** \file boundary.hpp
2 *
3 * Implementations and super-function for envelopes
4 */
5
6
7#include "boundary.hpp"
8
9#include<gsl/gsl_poly.h>
10
11// ========================================== F U N C T I O N S =================================
12
13
14/** Determines greatest diameters of a cluster defined by its convex envelope.
15 * Looks at lines parallel to one axis and where they intersect on the projected planes
16 * \param *out output stream for debugging
17 * \param *BoundaryPoints NDIM set of boundary points defining the convex envelope on each projected plane
18 * \param *mol molecule structure representing the cluster
19 * \param IsAngstroem whether we have angstroem or atomic units
20 * \return NDIM array of the diameters
21 */
22double *
23GetDiametersOfCluster(ofstream *out, Boundaries *BoundaryPtr, molecule *mol,
24 bool IsAngstroem)
25{
26 // get points on boundary of NULL was given as parameter
27 bool BoundaryFreeFlag = false;
28 Boundaries *BoundaryPoints = BoundaryPtr;
29 if (BoundaryPoints == NULL) {
30 BoundaryFreeFlag = true;
31 BoundaryPoints = GetBoundaryPoints(out, mol);
32 } else {
33 *out << Verbose(1) << "Using given boundary points set." << endl;
34 }
35 // determine biggest "diameter" of cluster for each axis
36 Boundaries::iterator Neighbour, OtherNeighbour;
37 double *GreatestDiameter = new double[NDIM];
38 for (int i = 0; i < NDIM; i++)
39 GreatestDiameter[i] = 0.;
40 double OldComponent, tmp, w1, w2;
41 Vector DistanceVector, OtherVector;
42 int component, Othercomponent;
43 for (int axis = 0; axis < NDIM; axis++)
44 { // regard each projected plane
45 //*out << Verbose(1) << "Current axis is " << axis << "." << endl;
46 for (int j = 0; j < 2; j++)
47 { // and for both axis on the current plane
48 component = (axis + j + 1) % NDIM;
49 Othercomponent = (axis + 1 + ((j + 1) & 1)) % NDIM;
50 //*out << Verbose(1) << "Current component is " << component << ", Othercomponent is " << Othercomponent << "." << endl;
51 for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner
52 != BoundaryPoints[axis].end(); runner++)
53 {
54 //*out << Verbose(2) << "Current runner is " << *(runner->second.second) << "." << endl;
55 // seek for the neighbours pair where the Othercomponent sign flips
56 Neighbour = runner;
57 Neighbour++;
58 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
59 Neighbour = BoundaryPoints[axis].begin();
60 DistanceVector.CopyVector(&runner->second.second->x);
61 DistanceVector.SubtractVector(&Neighbour->second.second->x);
62 do
63 { // seek for neighbour pair where it flips
64 OldComponent = DistanceVector.x[Othercomponent];
65 Neighbour++;
66 if (Neighbour == BoundaryPoints[axis].end()) // make it wrap around
67 Neighbour = BoundaryPoints[axis].begin();
68 DistanceVector.CopyVector(&runner->second.second->x);
69 DistanceVector.SubtractVector(&Neighbour->second.second->x);
70 //*out << Verbose(3) << "OldComponent is " << OldComponent << ", new one is " << DistanceVector.x[Othercomponent] << "." << endl;
71 }
72 while ((runner != Neighbour) && (fabs(OldComponent / fabs(
73 OldComponent) - DistanceVector.x[Othercomponent] / fabs(
74 DistanceVector.x[Othercomponent])) < MYEPSILON)); // as long as sign does not flip
75 if (runner != Neighbour)
76 {
77 OtherNeighbour = Neighbour;
78 if (OtherNeighbour == BoundaryPoints[axis].begin()) // make it wrap around
79 OtherNeighbour = BoundaryPoints[axis].end();
80 OtherNeighbour--;
81 //*out << Verbose(2) << "The pair, where the sign of OtherComponent flips, is: " << *(Neighbour->second.second) << " and " << *(OtherNeighbour->second.second) << "." << endl;
82 // now we have found the pair: Neighbour and OtherNeighbour
83 OtherVector.CopyVector(&runner->second.second->x);
84 OtherVector.SubtractVector(&OtherNeighbour->second.second->x);
85 //*out << Verbose(2) << "Distances to Neighbour and OtherNeighbour are " << DistanceVector.x[component] << " and " << OtherVector.x[component] << "." << endl;
86 //*out << Verbose(2) << "OtherComponents to Neighbour and OtherNeighbour are " << DistanceVector.x[Othercomponent] << " and " << OtherVector.x[Othercomponent] << "." << endl;
87 // do linear interpolation between points (is exact) to extract exact intersection between Neighbour and OtherNeighbour
88 w1 = fabs(OtherVector.x[Othercomponent]);
89 w2 = fabs(DistanceVector.x[Othercomponent]);
90 tmp = fabs((w1 * DistanceVector.x[component] + w2
91 * OtherVector.x[component]) / (w1 + w2));
92 // mark if it has greater diameter
93 //*out << Verbose(2) << "Comparing current greatest " << GreatestDiameter[component] << " to new " << tmp << "." << endl;
94 GreatestDiameter[component] = (GreatestDiameter[component]
95 > tmp) ? GreatestDiameter[component] : tmp;
96 } //else
97 //*out << Verbose(2) << "Saw no sign flip, probably top or bottom node." << endl;
98 }
99 }
100 }
101 *out << Verbose(0) << "RESULT: The biggest diameters are "
102 << GreatestDiameter[0] << " and " << GreatestDiameter[1] << " and "
103 << GreatestDiameter[2] << " " << (IsAngstroem ? "angstrom"
104 : "atomiclength") << "." << endl;
105
106 // free reference lists
107 if (BoundaryFreeFlag)
108 delete[] (BoundaryPoints);
109
110 return GreatestDiameter;
111}
112;
113
114/** Creates the objects in a VRML file.
115 * \param *out output stream for debugging
116 * \param *vrmlfile output stream for tecplot data
117 * \param *Tess Tesselation structure with constructed triangles
118 * \param *mol molecule structure with atom positions
119 */
120void write_vrml_file(ofstream *out, ofstream *vrmlfile, class Tesselation *Tess, class molecule *mol)
121{
122 atom *Walker = mol->start;
123 bond *Binder = mol->first;
124 int i;
125 Vector *center = mol->DetermineCenterOfAll(out);
126 if (vrmlfile != NULL) {
127 //cout << Verbose(1) << "Writing Raster3D file ... ";
128 *vrmlfile << "#VRML V2.0 utf8" << endl;
129 *vrmlfile << "#Created by molecuilder" << endl;
130 *vrmlfile << "#All atoms as spheres" << endl;
131 while (Walker->next != mol->end) {
132 Walker = Walker->next;
133 *vrmlfile << "Sphere {" << endl << " "; // 2 is sphere type
134 for (i=0;i<NDIM;i++)
135 *vrmlfile << Walker->x.x[i]-center->x[i] << " ";
136 *vrmlfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
137 }
138
139 *vrmlfile << "# All bonds as vertices" << endl;
140 while (Binder->next != mol->last) {
141 Binder = Binder->next;
142 *vrmlfile << "3" << endl << " "; // 2 is round-ended cylinder type
143 for (i=0;i<NDIM;i++)
144 *vrmlfile << Binder->leftatom->x.x[i]-center->x[i] << " ";
145 *vrmlfile << "\t0.03\t";
146 for (i=0;i<NDIM;i++)
147 *vrmlfile << Binder->rightatom->x.x[i]-center->x[i] << " ";
148 *vrmlfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour
149 }
150
151 *vrmlfile << "# All tesselation triangles" << endl;
152 for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) {
153 *vrmlfile << "1" << endl << " "; // 1 is triangle type
154 for (i=0;i<3;i++) { // print each node
155 for (int j=0;j<NDIM;j++) // and for each node all NDIM coordinates
156 *vrmlfile << TriangleRunner->second->endpoints[i]->node->node->x[j]-center->x[j] << " ";
157 *vrmlfile << "\t";
158 }
159 *vrmlfile << "1. 0. 0." << endl; // red as colour
160 *vrmlfile << "18" << endl << " 0.5 0.5 0.5" << endl; // 18 is transparency type for previous object
161 }
162 } else {
163 cerr << "ERROR: Given vrmlfile is " << vrmlfile << "." << endl;
164 }
165 delete(center);
166};
167
168/** Creates the objects in a raster3d file (renderable with a header.r3d).
169 * \param *out output stream for debugging
170 * \param *rasterfile output stream for tecplot data
171 * \param *Tess Tesselation structure with constructed triangles
172 * \param *mol molecule structure with atom positions
173 */
174void write_raster3d_file(ofstream *out, ofstream *rasterfile, class Tesselation *Tess, class molecule *mol)
175{
176 atom *Walker = mol->start;
177 bond *Binder = mol->first;
178 int i;
179 Vector *center = mol->DetermineCenterOfAll(out);
180 if (rasterfile != NULL) {
181 //cout << Verbose(1) << "Writing Raster3D file ... ";
182 *rasterfile << "# Raster3D object description, created by MoleCuilder" << endl;
183 *rasterfile << "@header.r3d" << endl;
184 *rasterfile << "# All atoms as spheres" << endl;
185 while (Walker->next != mol->end) {
186 Walker = Walker->next;
187 *rasterfile << "2" << endl << " "; // 2 is sphere type
188 for (i=0;i<NDIM;i++)
189 *rasterfile << Walker->x.x[i]-center->x[i] << " ";
190 *rasterfile << "\t0.1\t1. 1. 1." << endl; // radius 0.05 and white as colour
191 }
192
193 *rasterfile << "# All bonds as vertices" << endl;
194 while (Binder->next != mol->last) {
195 Binder = Binder->next;
196 *rasterfile << "3" << endl << " "; // 2 is round-ended cylinder type
197 for (i=0;i<NDIM;i++)
198 *rasterfile << Binder->leftatom->x.x[i]-center->x[i] << " ";
199 *rasterfile << "\t0.03\t";
200 for (i=0;i<NDIM;i++)
201 *rasterfile << Binder->rightatom->x.x[i]-center->x[i] << " ";
202 *rasterfile << "\t0.03\t0. 0. 1." << endl; // radius 0.05 and blue as colour
203 }
204
205 *rasterfile << "# All tesselation triangles" << endl;
206 *rasterfile << "8\n 25. -1. 1. 1. 1. 0.0 0 0 0 2\n SOLID 1.0 0.0 0.0\n BACKFACE 0.3 0.3 1.0 0 0\n";
207 for (TriangleMap::iterator TriangleRunner = Tess->TrianglesOnBoundary.begin(); TriangleRunner != Tess->TrianglesOnBoundary.end(); TriangleRunner++) {
208 *rasterfile << "1" << endl << " "; // 1 is triangle type
209 for (i=0;i<3;i++) { // print each node
210 for (int j=0;j<NDIM;j++) // and for each node all NDIM coordinates
211 *rasterfile << TriangleRunner->second->endpoints[i]->node->node->x[j]-center->x[j] << " ";
212 *rasterfile << "\t";
213 }
214 *rasterfile << "1. 0. 0." << endl; // red as colour
215 //*rasterfile << "18" << endl << " 0.5 0.5 0.5" << endl; // 18 is transparency type for previous object
216 }
217 *rasterfile << "9\n# terminating special property\n";
218 } else {
219 cerr << "ERROR: Given rasterfile is " << rasterfile << "." << endl;
220 }
221 delete(center);
222};
223
224/** This function creates the tecplot file, displaying the tesselation of the hull.
225 * \param *out output stream for debugging
226 * \param *tecplot output stream for tecplot data
227 * \param N arbitrary number to differentiate various zones in the tecplot format
228 */
229void write_tecplot_file(ofstream *out, ofstream *tecplot, class Tesselation *TesselStruct, class molecule *mol, int N)
230{
231 if (tecplot != NULL) {
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 if (!mol->TesselStruct->AddPoint(runner->second.second, 0))
479 *out << Verbose(3) << "WARNING: Point " << *(runner->second.second) << " is already present!" << endl;
480
481 *out << Verbose(2) << "I found " << mol->TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl;
482 // now we have the whole set of edge points in the BoundaryList
483
484 // listing for debugging
485 // *out << Verbose(1) << "Listing PointsOnBoundary:";
486 // for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
487 // *out << " " << *runner->second;
488 // }
489 // *out << endl;
490
491 // 3a. guess starting triangle
492 mol->TesselStruct->GuessStartingTriangle(out);
493
494 // 3b. go through all lines, that are not yet part of two triangles (only of one so far)
495 mol->TesselStruct->TesselateOnBoundary(out, mol);
496
497 // 3c. check whether all atoms lay inside the boundary, if not, add to boundary points, segment triangle into three with the new point
498 if (!mol->TesselStruct->InsertStraddlingPoints(out, mol, LCList))
499 *out << Verbose(1) << "Insertion of straddling points failed!" << endl;
500
501 *out << Verbose(2) << "I created " << mol->TesselStruct->TrianglesOnBoundary.size() << " intermediate triangles with " << mol->TesselStruct->LinesOnBoundary.size() << " lines and " << mol->TesselStruct->PointsOnBoundary.size() << " points." << endl;
502
503 // 4. Store triangles in tecplot file
504 if (filename != NULL) {
505 if (DoTecplotOutput) {
506 string OutputName(filename);
507 OutputName.append("_intermed");
508 OutputName.append(TecplotSuffix);
509 ofstream *tecplot = new ofstream(OutputName.c_str());
510 write_tecplot_file(out, tecplot, mol->TesselStruct, mol, 0);
511 tecplot->close();
512 delete(tecplot);
513 }
514 if (DoRaster3DOutput) {
515 string OutputName(filename);
516 OutputName.append("_intermed");
517 OutputName.append(Raster3DSuffix);
518 ofstream *rasterplot = new ofstream(OutputName.c_str());
519 write_raster3d_file(out, rasterplot, mol->TesselStruct, mol);
520 rasterplot->close();
521 delete(rasterplot);
522 }
523 }
524
525 // 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
526 if (!mol->TesselStruct->CorrectConcaveBaselines(out))
527 *out << Verbose(1) << "Correction of concave baselines failed!" << endl;
528
529 // 3e. we need another correction here, for TesselPoints that are below the surface (i.e. have an odd number of concave triangles surrounding it)
530// if (!mol->TesselStruct->CorrectConcaveTesselPoints(out))
531// *out << Verbose(1) << "Correction of concave tesselpoints failed!" << endl;
532
533 *out << Verbose(2) << "I created " << mol->TesselStruct->TrianglesOnBoundary.size() << " triangles with " << mol->TesselStruct->LinesOnBoundary.size() << " lines and " << mol->TesselStruct->PointsOnBoundary.size() << " points." << endl;
534
535 // 4. Store triangles in tecplot file
536 if (filename != NULL) {
537 if (DoTecplotOutput) {
538 string OutputName(filename);
539 OutputName.append(TecplotSuffix);
540 ofstream *tecplot = new ofstream(OutputName.c_str());
541 write_tecplot_file(out, tecplot, mol->TesselStruct, mol, 0);
542 tecplot->close();
543 delete(tecplot);
544 }
545 if (DoRaster3DOutput) {
546 string OutputName(filename);
547 OutputName.append(Raster3DSuffix);
548 ofstream *rasterplot = new ofstream(OutputName.c_str());
549 write_raster3d_file(out, rasterplot, mol->TesselStruct, mol);
550 rasterplot->close();
551 delete(rasterplot);
552 }
553 }
554
555
556 // free reference lists
557 if (BoundaryFreeFlag)
558 delete[] (BoundaryPoints);
559
560 cout << Verbose(1) << "End of find_convex_border" << endl;
561};
562
563/** Creates a convex envelope from a given non-convex one.
564 * -# We go through all PointsOnBoundary.
565 * -# We look at each of its lines and CheckConvexityCriterion().
566 * -# If any returns concave, this Point cannot be on the final convex envelope.
567 * -# Hence, we remove it and re-create all its triangles from its getCircleOfConnectedPoints()
568 * -# We calculate the additional volume
569 * -# We go over the points until none yields a concave spot anymore.
570 *
571 * Note: This routine - for free - calculates the difference in volume between convex and
572 * non-convex envelope, as the former is easy to calculate - VolumeOfConvexEnvelope() - it
573 * can be used to compute volumes of arbitrary shapes.
574 * \param *out output stream for debugging
575 * \param *TesselStruct non-convex envelope, is changed in return!
576 * \param *configuration contains IsAngstroem()
577 * \return volume difference between the non- and the created convex envelope
578 */
579double ConvexizeNonconvexEnvelope(ofstream *out, class Tesselation *TesselStruct)
580{
581 double volume = 0;
582 class BoundaryPointSet *point = NULL;
583 class BoundaryLineSet *line = NULL;
584 class BoundaryTriangleSet *triangle = NULL;
585 Vector OldPoint, TetraederVector[3];
586 *out << Verbose(0) << "Begin of ConvexizeNonconvexEnvelope" << endl;
587
588 if (TesselStruct == NULL) {
589 *out << Verbose(1) << "ERROR: TesselStruct is empty!" << endl;
590 return volume;
591 }
592
593 bool AllConvex = true;
594 bool Convexity = false;
595 do {
596 AllConvex = true;
597 for (PointMap::iterator PointRunner = TesselStruct->PointsOnBoundary.begin(); PointRunner != TesselStruct->PointsOnBoundary.end(); PointRunner++) {
598 point = PointRunner->second;
599 *out << Verbose(1) << "INFO: Current point is " << *point << "." << endl;
600 Convexity = true;
601 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++) {
602 line = LineRunner->second;
603 *out << Verbose(2) << "INFO: Current line is " << *line << "." << endl;
604 if (line->CheckConvexityCriterion(out)) {
605 // convex
606 } else { // concave
607 Convexity = false; // we have to go again through all ...
608 break; // no need to check the others too
609 }
610 }
611 AllConvex = AllConvex && Convexity;
612 if (!Convexity) {
613 *out << Verbose(1) << "... point cannot be on convex envelope." << endl;
614 OldPoint.CopyVector(point->node->node);
615 // get list of connected points
616 BoundaryPointSet *Otherpoint = line->GetOtherEndpoint(point);
617 list<TesselPoint*> *CircleofPoints = TesselStruct->getCircleOfConnectedPoints(out, point->node, Otherpoint->node->node);
618 // remove all triangles
619 int *numbers = NULL;
620 int count = 0;
621 int i=0;
622 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++)
623 count+=LineRunner->second->triangles.size();
624 numbers = new int[count];
625 for (LineMap::iterator LineRunner = point->lines.begin(); LineRunner != point->lines.end(); LineRunner++) {
626 line = LineRunner->second;
627 for (TriangleMap::iterator TriangleRunner = line->triangles.begin(); TriangleRunner != line->triangles.end(); TriangleRunner++) {
628 triangle = TriangleRunner->second;
629 *out << Verbose(2) << "Erasing triangle " << *triangle << "." << endl;
630 numbers[i] = triangle->Nr;
631 TesselStruct->TrianglesOnBoundary.erase(triangle->Nr);
632 delete(triangle);
633 i++;
634 }
635 }
636 *out << Verbose(1) << i << " triangles were removed." << endl;
637
638 // re-create all triangles by going through connected points list
639 list<TesselPoint*>::iterator OtherCircleRunner = CircleofPoints->end();
640 OtherCircleRunner--;
641 i=0;
642 for (list<TesselPoint*>::iterator CircleRunner = CircleofPoints->begin(); CircleRunner != CircleofPoints->end(); CircleRunner++) {
643 *out << Verbose(2) << "Adding new triangle points."<< endl;
644 TesselStruct->AddPoint(point->node, 0);
645 TesselStruct->AddPoint(*CircleRunner, 1);
646 TesselStruct->AddPoint(*OtherCircleRunner, 2);
647 *out << Verbose(2) << "Adding new triangle lines."<< endl;
648 TesselStruct->AddTriangleLine(TesselStruct->BPS[0], TesselStruct->BPS[1], 0);
649 TesselStruct->AddTriangleLine(TesselStruct->BPS[0], TesselStruct->BPS[2], 1);
650 TesselStruct->AddTriangleLine(TesselStruct->BPS[1], TesselStruct->BPS[2], 2);
651 TesselStruct->BTS = new class BoundaryTriangleSet(TesselStruct->BLS, numbers[i]);
652 TesselStruct->TrianglesOnBoundary.insert(TrianglePair(numbers[i], triangle));
653 *out << Verbose(2) << "Created triangle " << *TesselStruct->BTS << "." << endl;
654 // calculate volume summand as a general tetraeder
655 for (int j=0;j<3;j++) {
656 TetraederVector[j].CopyVector(TesselStruct->BPS[j]->node->node);
657 TetraederVector[j].SubtractVector(&OldPoint);
658 }
659 OldPoint.CopyVector(&TetraederVector[0]);
660 OldPoint.VectorProduct(&TetraederVector[1]);
661 volume += 1./6. * fabs(OldPoint.ScalarProduct(&TetraederVector[2]));
662 // advance other shank
663 OtherCircleRunner++;
664 if (OtherCircleRunner == CircleofPoints->end())
665 OtherCircleRunner = CircleofPoints->begin();
666 // advance number
667 i++;
668 if (i > count)
669 *out << Verbose(2) << "WARNING: Maximum of numbers reached!" << endl;
670 }
671 *out << Verbose(1) << i << " triangles were created." << endl;
672
673 delete[](numbers);
674 }
675 }
676 } while (!AllConvex);
677 *out << Verbose(0) << "End of ConvexizeNonconvexEnvelope" << endl;
678
679 // end
680 return volume;
681};
682
683/** Determines the volume of a cluster.
684 * Determines first the convex envelope, then tesselates it and calculates its volume.
685 * \param *out output stream for debugging
686 * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
687 * \param *configuration needed for path to store convex envelope file
688 * \return determined volume of the cluster in cubed config:GetIsAngstroem()
689 */
690double VolumeOfConvexEnvelope(ofstream *out, class Tesselation *TesselStruct, class config *configuration)
691{
692 bool IsAngstroem = configuration->GetIsAngstroem();
693 double volume = 0.;
694 double PyramidVolume = 0.;
695 double G, h;
696 Vector x, y;
697 double a, b, c;
698
699 // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
700 *out << Verbose(1)
701 << "Calculating the volume of the pyramids formed out of triangles and center of gravity."
702 << endl;
703 for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++)
704 { // go through every triangle, calculate volume of its pyramid with CoG as peak
705 x.CopyVector(runner->second->endpoints[0]->node->node);
706 x.SubtractVector(runner->second->endpoints[1]->node->node);
707 y.CopyVector(runner->second->endpoints[0]->node->node);
708 y.SubtractVector(runner->second->endpoints[2]->node->node);
709 a = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
710 b = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[2]->node->node));
711 c = sqrt(runner->second->endpoints[2]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
712 G = sqrt(((a + b + c) * (a + b + c) - 2 * (a * a + b * b + c * c)) / 16.); // area of tesselated triangle
713 x.MakeNormalVector(runner->second->endpoints[0]->node->node, runner->second->endpoints[1]->node->node, runner->second->endpoints[2]->node->node);
714 x.Scale(runner->second->endpoints[1]->node->node->Projection(&x));
715 h = x.Norm(); // distance of CoG to triangle
716 PyramidVolume = (1. / 3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
717 *out << Verbose(2) << "Area of triangle is " << G << " "
718 << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is "
719 << h << " and the volume is " << PyramidVolume << " "
720 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
721 volume += PyramidVolume;
722 }
723 *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10)
724 << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3."
725 << endl;
726
727 return volume;
728}
729;
730
731/** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
732 * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
733 * \param *out output stream for debugging
734 * \param *configuration needed for path to store convex envelope file
735 * \param *mol molecule structure representing the cluster
736 * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead.
737 * \param celldensity desired average density in final cell
738 */
739void
740PrepareClustersinWater(ofstream *out, config *configuration, molecule *mol,
741 double ClusterVolume, double celldensity)
742{
743 // transform to PAS
744 mol->PrincipalAxisSystem(out, true);
745
746 // some preparations beforehand
747 bool IsAngstroem = configuration->GetIsAngstroem();
748 Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol);
749 class Tesselation *TesselStruct = NULL;
750 LinkedCell LCList(mol, 10.);
751 Find_convex_border(out, mol, &LCList, NULL);
752 double clustervolume;
753 if (ClusterVolume == 0)
754 clustervolume = VolumeOfConvexEnvelope(out, TesselStruct, configuration);
755 else
756 clustervolume = ClusterVolume;
757 double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, IsAngstroem);
758 Vector BoxLengths;
759 int repetition[NDIM] =
760 { 1, 1, 1 };
761 int TotalNoClusters = 1;
762 for (int i = 0; i < NDIM; i++)
763 TotalNoClusters *= repetition[i];
764
765 // sum up the atomic masses
766 double totalmass = 0.;
767 atom *Walker = mol->start;
768 while (Walker->next != mol->end)
769 {
770 Walker = Walker->next;
771 totalmass += Walker->type->mass;
772 }
773 *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10)
774 << totalmass << " atomicmassunit." << endl;
775
776 *out << Verbose(0) << "RESULT: The average density is " << setprecision(10)
777 << totalmass / clustervolume << " atomicmassunit/"
778 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
779
780 // solve cubic polynomial
781 *out << Verbose(1) << "Solving equidistant suspension in water problem ..."
782 << endl;
783 double cellvolume;
784 if (IsAngstroem)
785 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_A - (totalmass
786 / clustervolume)) / (celldensity - 1);
787 else
788 cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_a0 - (totalmass
789 / clustervolume)) / (celldensity - 1);
790 *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity
791 << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom"
792 : "atomiclength") << "^3." << endl;
793
794 double minimumvolume = TotalNoClusters * (GreatestDiameter[0]
795 * GreatestDiameter[1] * GreatestDiameter[2]);
796 *out << Verbose(1)
797 << "Minimum volume of the convex envelope contained in a rectangular box is "
798 << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom"
799 : "atomiclength") << "^3." << endl;
800 if (minimumvolume > cellvolume)
801 {
802 cerr << Verbose(0)
803 << "ERROR: the containing box already has a greater volume than the envisaged cell volume!"
804 << endl;
805 cout << Verbose(0)
806 << "Setting Box dimensions to minimum possible, the greatest diameters."
807 << endl;
808 for (int i = 0; i < NDIM; i++)
809 BoxLengths.x[i] = GreatestDiameter[i];
810 mol->CenterEdge(out, &BoxLengths);
811 }
812 else
813 {
814 BoxLengths.x[0] = (repetition[0] * GreatestDiameter[0] + repetition[1]
815 * GreatestDiameter[1] + repetition[2] * GreatestDiameter[2]);
816 BoxLengths.x[1] = (repetition[0] * repetition[1] * GreatestDiameter[0]
817 * GreatestDiameter[1] + repetition[0] * repetition[2]
818 * GreatestDiameter[0] * GreatestDiameter[2] + repetition[1]
819 * repetition[2] * GreatestDiameter[1] * GreatestDiameter[2]);
820 BoxLengths.x[2] = minimumvolume - cellvolume;
821 double x0 = 0., x1 = 0., x2 = 0.;
822 if (gsl_poly_solve_cubic(BoxLengths.x[0], BoxLengths.x[1],
823 BoxLengths.x[2], &x0, &x1, &x2) == 1) // either 1 or 3 on return
824 *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0
825 << " ." << endl;
826 else
827 {
828 *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0
829 << " and " << x1 << " and " << x2 << " ." << endl;
830 x0 = x2; // sorted in ascending order
831 }
832
833 cellvolume = 1;
834 for (int i = 0; i < NDIM; i++)
835 {
836 BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]);
837 cellvolume *= BoxLengths.x[i];
838 }
839
840 // set new box dimensions
841 *out << Verbose(0) << "Translating to box with these boundaries." << endl;
842 mol->SetBoxDimension(&BoxLengths);
843 mol->CenterInBox((ofstream *) &cout);
844 }
845 // update Box of atoms by boundary
846 mol->SetBoxDimension(&BoxLengths);
847 *out << Verbose(0) << "RESULT: The resulting cell dimensions are: "
848 << BoxLengths.x[0] << " and " << BoxLengths.x[1] << " and "
849 << BoxLengths.x[2] << " with total volume of " << cellvolume << " "
850 << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
851}
852;
853
854
855/** Fills the empty space of the simulation box with water/
856 * \param *out output stream for debugging
857 * \param *List list of molecules already present in box
858 * \param *TesselStruct contains tesselated surface
859 * \param *filler molecule which the box is to be filled with
860 * \param configuration contains box dimensions
861 * \param distance[NDIM] distance between filling molecules in each direction
862 * \param RandAtomDisplacement maximum distance for random displacement per atom
863 * \param RandMolDisplacement maximum distance for random displacement per filler molecule
864 * \param DoRandomRotation true - do random rotiations, false - don't
865 * \return *mol pointer to new molecule with filled atoms
866 */
867molecule * FillBoxWithMolecule(ofstream *out, MoleculeListClass *List, molecule *filler, config &configuration, double distance[NDIM], double RandomAtomDisplacement, double RandomMolDisplacement, bool DoRandomRotation)
868{
869 molecule *Filling = new molecule(filler->elemente);
870 Vector CurrentPosition;
871 int N[NDIM];
872 int n[NDIM];
873 double *M = filler->ReturnFullMatrixforSymmetric(filler->cell_size);
874 double Rotations[NDIM*NDIM];
875 Vector AtomTranslations;
876 Vector FillerTranslations;
877 Vector FillerDistance;
878 double FillIt = false;
879 atom *Walker = NULL;
880 bond *Binder = NULL;
881 int i;
882 LinkedCell *LCList[List->ListOfMolecules.size()];
883
884 *out << Verbose(0) << "Begin of FillBoxWithMolecule" << endl;
885
886 i=0;
887 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
888 *out << Verbose(1) << "Pre-creating linked cell lists for molecule " << *ListRunner << "." << endl;
889 LCList[i] = new LinkedCell((*ListRunner), 5.); // get linked cell list
890 if ((*ListRunner)->TesselStruct == NULL) {
891 *out << Verbose(1) << "Pre-creating tesselation for molecule " << *ListRunner << "." << endl;
892 Find_non_convex_border((ofstream *)&cout, (*ListRunner), LCList[i], NULL, 5.);
893 }
894 i++;
895 }
896
897 // Center filler at origin
898 filler->CenterOrigin(out);
899 filler->Center.Zero();
900
901 filler->CountAtoms(out);
902 atom * CopyAtoms[filler->AtomCount];
903 int nr = 0;
904
905 // calculate filler grid in [0,1]^3
906 FillerDistance.Init(distance[0], distance[1], distance[2]);
907 FillerDistance.InverseMatrixMultiplication(M);
908 *out << Verbose(1) << "INFO: Grid steps are ";
909 for(int i=0;i<NDIM;i++) {
910 N[i] = (int) ceil(1./FillerDistance.x[i]);
911 *out << N[i];
912 if (i != NDIM-1)
913 *out<< ", ";
914 else
915 *out << "." << endl;
916 }
917
918 // go over [0,1]^3 filler grid
919 for (n[0] = 0; n[0] < N[0]; n[0]++)
920 for (n[1] = 0; n[1] < N[1]; n[1]++)
921 for (n[2] = 0; n[2] < N[2]; n[2]++) {
922 // calculate position of current grid vector in untransformed box
923 CurrentPosition.Init((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
924 CurrentPosition.MatrixMultiplication(M);
925 *out << Verbose(2) << "INFO: Current Position is " << CurrentPosition << "." << endl;
926 // Check whether point is in- or outside
927 FillIt = true;
928 i=0;
929 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
930 // get linked cell list
931 if ((*ListRunner)->TesselStruct == NULL) {
932 *out << Verbose(1) << "ERROR: TesselStruct of " << (*ListRunner) << " is NULL. Didn't we pre-create it?" << endl;
933 FillIt = false;
934 } else
935 FillIt = FillIt && (!(*ListRunner)->TesselStruct->IsInnerPoint(out, CurrentPosition, LCList[i++]));
936 }
937
938 if (FillIt) {
939 // fill in Filler
940 *out << Verbose(2) << "Space at " << CurrentPosition << " is unoccupied by any molecule, filling in." << endl;
941
942 // create molecule random translation vector ...
943 for (int i=0;i<NDIM;i++)
944 FillerTranslations.x[i] = RandomMolDisplacement*(rand()/(RAND_MAX/2.) - 1.);
945 *out << Verbose(3) << "INFO: Translating this filler by " << FillerTranslations << "." << endl;
946
947 // go through all atoms
948 nr=0;
949 Walker = filler->start;
950 while (Walker->next != filler->end) {
951 Walker = Walker->next;
952 // copy atom ...
953 CopyAtoms[Walker->nr] = new atom(Walker);
954
955 // create atomic random translation vector ...
956 for (int i=0;i<NDIM;i++)
957 AtomTranslations.x[i] = RandomAtomDisplacement*(rand()/(RAND_MAX/2.) - 1.);
958
959 // ... and rotation matrix
960 if (DoRandomRotation) {
961 double phi[NDIM];
962 for (int i=0;i<NDIM;i++) {
963 phi[i] = rand()/(RAND_MAX/(2.*M_PI));
964 }
965
966 Rotations[0] = cos(phi[0]) *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2]));
967 Rotations[3] = sin(phi[0]) *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2]));
968 Rotations[6] = cos(phi[1])*sin(phi[2]) ;
969 Rotations[1] = - sin(phi[0])*cos(phi[1]) ;
970 Rotations[4] = cos(phi[0])*cos(phi[1]) ;
971 Rotations[7] = sin(phi[1]) ;
972 Rotations[3] = - cos(phi[0]) *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2]));
973 Rotations[5] = - sin(phi[0]) *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2]));
974 Rotations[8] = cos(phi[1])*cos(phi[2]) ;
975 }
976
977 // ... and put at new position
978 if (DoRandomRotation)
979 CopyAtoms[Walker->nr]->x.MatrixMultiplication(Rotations);
980 CopyAtoms[Walker->nr]->x.AddVector(&AtomTranslations);
981 CopyAtoms[Walker->nr]->x.AddVector(&FillerTranslations);
982 CopyAtoms[Walker->nr]->x.AddVector(&CurrentPosition);
983
984 // insert into Filling
985
986 // FIXME: gives completely different results if CopyAtoms[..] used instead of Walker, why???
987 *out << Verbose(4) << "Filling atom " << *Walker << ", translated to " << AtomTranslations << ", at final position is " << (CopyAtoms[Walker->nr]->x) << "." << endl;
988 Filling->AddAtom(CopyAtoms[Walker->nr]);
989 }
990
991 // go through all bonds and add as well
992 Binder = filler->first;
993 while(Binder->next != filler->last) {
994 Binder = Binder->next;
995 *out << Verbose(3) << "Adding Bond between " << *CopyAtoms[Binder->leftatom->nr] << " and " << *CopyAtoms[Binder->rightatom->nr]<< "." << endl;
996 Filling->AddBond(CopyAtoms[Binder->leftatom->nr], CopyAtoms[Binder->rightatom->nr], Binder->BondDegree);
997 }
998 } else {
999 // leave empty
1000 *out << Verbose(2) << "Space at " << CurrentPosition << " is occupied." << endl;
1001 }
1002 }
1003 *out << Verbose(0) << "End of FillBoxWithMolecule" << endl;
1004
1005 return Filling;
1006};
1007
1008
1009/** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
1010 * \param *out output stream for debugging
1011 * \param *mol molecule structure with Atom's and Bond's
1012 * \param *Tess Tesselation filled with points, lines and triangles on boundary on return
1013 * \param *LCList atoms in LinkedCell list
1014 * \param *filename filename prefix for output of vertex data
1015 * \para RADIUS radius of the virtual sphere
1016 */
1017void Find_non_convex_border(ofstream *out, molecule* mol, class LinkedCell *LCList, const char *filename, const double RADIUS)
1018{
1019 int N = 0;
1020 bool freeLC = false;
1021 ofstream *tempstream = NULL;
1022 char NumberName[255];
1023 int TriangleFilesWritten = 0;
1024
1025 *out << Verbose(1) << "Entering search for non convex hull. " << endl;
1026 if (mol->TesselStruct == NULL) {
1027 *out << Verbose(1) << "Allocating Tesselation struct ..." << endl;
1028 mol->TesselStruct = new Tesselation;
1029 } else {
1030 delete(mol->TesselStruct);
1031 *out << Verbose(1) << "Re-Allocating Tesselation struct ..." << endl;
1032 mol->TesselStruct = new Tesselation;
1033 }
1034 LineMap::iterator baseline;
1035 LineMap::iterator testline;
1036 *out << Verbose(0) << "Begin of Find_non_convex_border\n";
1037 bool flag = false; // marks whether we went once through all baselines without finding any without two triangles
1038 bool failflag = false;
1039
1040 if (LCList == NULL) {
1041 LCList = new LinkedCell(mol, 2.*RADIUS);
1042 freeLC = true;
1043 }
1044
1045 mol->TesselStruct->Find_starting_triangle(out, RADIUS, LCList);
1046
1047 baseline = mol->TesselStruct->LinesOnBoundary.begin();
1048 // the outward most line is dangerous, as we may end up with wrapping up the starting triangle, hence
1049 // terminating the algorithm too early.
1050 if (baseline != mol->TesselStruct->LinesOnBoundary.end()) // skip first line as it its the outwardmost!
1051 baseline++;
1052 while ((baseline != mol->TesselStruct->LinesOnBoundary.end()) || (flag)) {
1053 if (baseline->second->triangles.size() == 1) {
1054 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.
1055 flag = flag || failflag;
1056 if (!failflag)
1057 cerr << "WARNING: Find_next_suitable_triangle failed." << endl;
1058 // write temporary envelope
1059 if ((DoSingleStepOutput && (mol->TesselStruct->TrianglesOnBoundaryCount % SingleStepWidth == 0))) { // if we have a new triangle and want to output each new triangle configuration
1060 TriangleMap::iterator runner = mol->TesselStruct->TrianglesOnBoundary.end();
1061 runner--;
1062 class BoundaryTriangleSet *triangle = runner->second;
1063 if (triangle != NULL) {
1064 sprintf(NumberName, "-%04d-%s_%s_%s", TriangleFilesWritten, triangle->endpoints[0]->node->Name, triangle->endpoints[1]->node->Name, triangle->endpoints[2]->node->Name);
1065 if (DoTecplotOutput) {
1066 string NameofTempFile(filename);
1067 NameofTempFile.append(NumberName);
1068 for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
1069 NameofTempFile.erase(npos, 1);
1070 NameofTempFile.append(TecplotSuffix);
1071 *out << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
1072 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
1073 write_tecplot_file(out, tempstream, mol->TesselStruct, mol, TriangleFilesWritten);
1074 tempstream->close();
1075 tempstream->flush();
1076 delete(tempstream);
1077 }
1078
1079 if (DoRaster3DOutput) {
1080 string NameofTempFile(filename);
1081 NameofTempFile.append(NumberName);
1082 for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
1083 NameofTempFile.erase(npos, 1);
1084 NameofTempFile.append(Raster3DSuffix);
1085 *out << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
1086 tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
1087 write_raster3d_file(out, tempstream, mol->TesselStruct, mol);
1088 // // include the current position of the virtual sphere in the temporary raster3d file
1089 // // make the circumsphere's center absolute again
1090 // helper.CopyVector(BaseRay->endpoints[0]->node->node);
1091 // helper.AddVector(BaseRay->endpoints[1]->node->node);
1092 // helper.Scale(0.5);
1093 // (*it)->OptCenter.AddVector(&helper);
1094 // Vector *center = mol->DetermineCenterOfAll(out);
1095 // (*it)->OptCenter.SubtractVector(center);
1096 // delete(center);
1097 // // and add to file plus translucency object
1098 // *tempstream << "# current virtual sphere\n";
1099 // *tempstream << "8\n 25.0 0.6 -1.0 -1.0 -1.0 0.2 0 0 0 0\n";
1100 // *tempstream << "2\n " << (*it)->OptCenter.x[0] << " "
1101 // << (*it)->OptCenter.x[1] << " " << (*it)->OptCenter.x[2]
1102 // << "\t" << RADIUS << "\t1 0 0\n";
1103 // *tempstream << "9\n terminating special property\n";
1104 tempstream->close();
1105 tempstream->flush();
1106 delete(tempstream);
1107 }
1108 }
1109 if (DoTecplotOutput || DoRaster3DOutput)
1110 TriangleFilesWritten++;
1111 }
1112 } else {
1113 //cout << Verbose(1) << "Line " << *baseline->second << " has " << baseline->second->triangles.size() << " triangles adjacent" << endl;
1114 if (baseline->second->triangles.size() != 2)
1115 *out << Verbose(1) << "ERROR: TESSELATION FINISHED WITH INVALID TRIANGLE COUNT!" << endl;
1116 }
1117
1118 N++;
1119 baseline++;
1120 if ((baseline == mol->TesselStruct->LinesOnBoundary.end()) && (flag)) {
1121 baseline = mol->TesselStruct->LinesOnBoundary.begin(); // restart if we reach end due to newly inserted lines
1122 flag = false;
1123 }
1124 }
1125
1126 // write final envelope
1127 if (filename != 0) {
1128 *out << Verbose(1) << "Writing final tecplot file\n";
1129 if (DoTecplotOutput) {
1130 string OutputName(filename);
1131 OutputName.append(TecplotSuffix);
1132 ofstream *tecplot = new ofstream(OutputName.c_str());
1133 write_tecplot_file(out, tecplot, mol->TesselStruct, mol, -1);
1134 tecplot->close();
1135 delete(tecplot);
1136 }
1137 if (DoRaster3DOutput) {
1138 string OutputName(filename);
1139 OutputName.append(Raster3DSuffix);
1140 ofstream *raster = new ofstream(OutputName.c_str());
1141 write_raster3d_file(out, raster, mol->TesselStruct, mol);
1142 raster->close();
1143 delete(raster);
1144 }
1145 } else {
1146 cerr << "ERROR: Could definitively not find all necessary triangles!" << endl;
1147 }
1148
1149 cout << Verbose(2) << "Check: List of Baselines with not two connected triangles:" << endl;
1150 int counter = 0;
1151 for (testline = mol->TesselStruct->LinesOnBoundary.begin(); testline != mol->TesselStruct->LinesOnBoundary.end(); testline++) {
1152 if (testline->second->triangles.size() != 2) {
1153 cout << Verbose(2) << *testline->second << "\t" << testline->second->triangles.size() << endl;
1154 counter++;
1155 }
1156 }
1157 if (counter == 0)
1158 *out << Verbose(2) << "None." << endl;
1159
1160// // Tests the IsInnerAtom() function.
1161// Vector x (0, 0, 0);
1162// *out << Verbose(0) << "Point to check: " << x << endl;
1163// *out << Verbose(0) << "Check: IsInnerPoint() returns " << mol->TesselStruct->IsInnerPoint(out, x, LCList)
1164// << "for vector " << x << "." << endl;
1165// TesselPoint* a = mol->TesselStruct->PointsOnBoundary.begin()->second->node;
1166// *out << Verbose(0) << "Point to check: " << *a << " (on boundary)." << endl;
1167// *out << Verbose(0) << "Check: IsInnerAtom() returns " << mol->TesselStruct->IsInnerPoint(out, a, LCList)
1168// << "for atom " << a << " (on boundary)." << endl;
1169// LinkedNodes *List = NULL;
1170// for (int i=0;i<NDIM;i++) { // each axis
1171// LCList->n[i] = LCList->N[i]-1; // current axis is topmost cell
1172// for (LCList->n[(i+1)%NDIM]=0;LCList->n[(i+1)%NDIM]<LCList->N[(i+1)%NDIM];LCList->n[(i+1)%NDIM]++)
1173// for (LCList->n[(i+2)%NDIM]=0;LCList->n[(i+2)%NDIM]<LCList->N[(i+2)%NDIM];LCList->n[(i+2)%NDIM]++) {
1174// List = LCList->GetCurrentCell();
1175// //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
1176// if (List != NULL) {
1177// for (LinkedNodes::iterator Runner = List->begin();Runner != List->end();Runner++) {
1178// if (mol->TesselStruct->PointsOnBoundary.find((*Runner)->nr) == mol->TesselStruct->PointsOnBoundary.end()) {
1179// a = *Runner;
1180// i=3;
1181// for (int j=0;j<NDIM;j++)
1182// LCList->n[j] = LCList->N[j];
1183// break;
1184// }
1185// }
1186// }
1187// }
1188// }
1189// *out << Verbose(0) << "Check: IsInnerPoint() returns " << mol->TesselStruct->IsInnerPoint(out, a, LCList)
1190// << "for atom " << a << " (inside)." << endl;
1191
1192
1193 if (freeLC)
1194 delete(LCList);
1195 *out << Verbose(0) << "End of Find_non_convex_border\n";
1196};
1197
1198/** Finds a hole of sufficient size in \a this molecule to embed \a *srcmol into it.
1199 * \param *out output stream for debugging
1200 * \param *srcmol molecule to embed into
1201 * \return *Vector new center of \a *srcmol for embedding relative to \a this
1202 */
1203Vector* molecule::FindEmbeddingHole(ofstream *out, molecule *srcmol)
1204{
1205 Vector *Center = new Vector;
1206 Center->Zero();
1207 // calculate volume/shape of \a *srcmol
1208
1209 // find embedding holes
1210
1211 // if more than one, let user choose
1212
1213 // return embedding center
1214 return Center;
1215};
1216
Note: See TracBrowser for help on using the repository browser.