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 | */
|
---|
22 | double *
|
---|
23 | GetDiametersOfCluster(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 | */
|
---|
120 | void 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 | */
|
---|
174 | void 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 | */
|
---|
229 | void 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 | */
|
---|
267 | Boundaries *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 | */
|
---|
441 | void Find_convex_border(ofstream *out, molecule* mol, class LinkedCell *LCList, const char *filename)
|
---|
442 | {
|
---|
443 | bool BoundaryFreeFlag = false;
|
---|
444 | Boundaries *BoundaryPoints = NULL;
|
---|
445 |
|
---|
446 | cout << Verbose(1) << "Begin of find_convex_border" << endl;
|
---|
447 |
|
---|
448 | if (mol->TesselStruct != NULL) // free if allocated
|
---|
449 | delete(mol->TesselStruct);
|
---|
450 | mol->TesselStruct = new class Tesselation;
|
---|
451 |
|
---|
452 | // 1. Find all points on the boundary
|
---|
453 | if (BoundaryPoints == NULL) {
|
---|
454 | BoundaryFreeFlag = true;
|
---|
455 | BoundaryPoints = GetBoundaryPoints(out, mol);
|
---|
456 | } else {
|
---|
457 | *out << Verbose(1) << "Using given boundary points set." << endl;
|
---|
458 | }
|
---|
459 |
|
---|
460 | // printing all inserted for debugging
|
---|
461 | for (int axis=0; axis < NDIM; axis++)
|
---|
462 | {
|
---|
463 | *out << Verbose(2) << "Printing list of candidates for axis " << axis << " which we have inserted so far." << endl;
|
---|
464 | int i=0;
|
---|
465 | for(Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++) {
|
---|
466 | if (runner != BoundaryPoints[axis].begin())
|
---|
467 | *out << ", " << i << ": " << *runner->second.second;
|
---|
468 | else
|
---|
469 | *out << i << ": " << *runner->second.second;
|
---|
470 | i++;
|
---|
471 | }
|
---|
472 | *out << endl;
|
---|
473 | }
|
---|
474 |
|
---|
475 | // 2. fill the boundary point list
|
---|
476 | for (int axis = 0; axis < NDIM; axis++)
|
---|
477 | for (Boundaries::iterator runner = BoundaryPoints[axis].begin(); runner != BoundaryPoints[axis].end(); runner++)
|
---|
478 | mol->TesselStruct->AddPoint(runner->second.second);
|
---|
479 |
|
---|
480 | *out << Verbose(2) << "I found " << mol->TesselStruct->PointsOnBoundaryCount << " points on the convex boundary." << endl;
|
---|
481 | // now we have the whole set of edge points in the BoundaryList
|
---|
482 |
|
---|
483 | // listing for debugging
|
---|
484 | // *out << Verbose(1) << "Listing PointsOnBoundary:";
|
---|
485 | // for(PointMap::iterator runner = PointsOnBoundary.begin(); runner != PointsOnBoundary.end(); runner++) {
|
---|
486 | // *out << " " << *runner->second;
|
---|
487 | // }
|
---|
488 | // *out << endl;
|
---|
489 |
|
---|
490 | // 3a. guess starting triangle
|
---|
491 | mol->TesselStruct->GuessStartingTriangle(out);
|
---|
492 |
|
---|
493 | // 3b. go through all lines, that are not yet part of two triangles (only of one so far)
|
---|
494 | mol->TesselStruct->TesselateOnBoundary(out, mol);
|
---|
495 |
|
---|
496 | // 3c. check whether all atoms lay inside the boundary, if not, add to boundary points, segment triangle into three with the new point
|
---|
497 | if (!mol->TesselStruct->InsertStraddlingPoints(out, mol, LCList))
|
---|
498 | *out << Verbose(1) << "Insertion of straddling points failed!" << endl;
|
---|
499 |
|
---|
500 | *out << Verbose(2) << "I created " << mol->TesselStruct->TrianglesOnBoundary.size() << " intermediate triangles with " << mol->TesselStruct->LinesOnBoundary.size() << " lines and " << mol->TesselStruct->PointsOnBoundary.size() << " points." << endl;
|
---|
501 |
|
---|
502 | // 4. Store triangles in tecplot file
|
---|
503 | if (filename != NULL) {
|
---|
504 | if (DoTecplotOutput) {
|
---|
505 | string OutputName(filename);
|
---|
506 | OutputName.append("_intermed");
|
---|
507 | OutputName.append(TecplotSuffix);
|
---|
508 | ofstream *tecplot = new ofstream(OutputName.c_str());
|
---|
509 | write_tecplot_file(out, tecplot, mol->TesselStruct, mol, 0);
|
---|
510 | tecplot->close();
|
---|
511 | delete(tecplot);
|
---|
512 | }
|
---|
513 | if (DoRaster3DOutput) {
|
---|
514 | string OutputName(filename);
|
---|
515 | OutputName.append("_intermed");
|
---|
516 | OutputName.append(Raster3DSuffix);
|
---|
517 | ofstream *rasterplot = new ofstream(OutputName.c_str());
|
---|
518 | write_raster3d_file(out, rasterplot, mol->TesselStruct, mol);
|
---|
519 | rasterplot->close();
|
---|
520 | delete(rasterplot);
|
---|
521 | }
|
---|
522 | }
|
---|
523 |
|
---|
524 | // 3d. check all baselines whether the peaks of the two adjacent triangles with respect to center of baseline are convex, if not, make the baseline between the two peaks and baseline endpoints become the new peaks
|
---|
525 | if (!mol->TesselStruct->CorrectConcaveBaselines(out))
|
---|
526 | *out << Verbose(1) << "Correction of concave baselines failed!" << endl;
|
---|
527 |
|
---|
528 | // 3e. we need another correction here, for TesselPoints that are below the surface (i.e. have an odd number of concave triangles surrounding it)
|
---|
529 | // if (!mol->TesselStruct->CorrectConcaveTesselPoints(out))
|
---|
530 | // *out << Verbose(1) << "Correction of concave tesselpoints failed!" << endl;
|
---|
531 |
|
---|
532 | *out << Verbose(2) << "I created " << mol->TesselStruct->TrianglesOnBoundary.size() << " triangles with " << mol->TesselStruct->LinesOnBoundary.size() << " lines and " << mol->TesselStruct->PointsOnBoundary.size() << " points." << endl;
|
---|
533 |
|
---|
534 | // 4. Store triangles in tecplot file
|
---|
535 | if (filename != NULL) {
|
---|
536 | if (DoTecplotOutput) {
|
---|
537 | string OutputName(filename);
|
---|
538 | OutputName.append(TecplotSuffix);
|
---|
539 | ofstream *tecplot = new ofstream(OutputName.c_str());
|
---|
540 | write_tecplot_file(out, tecplot, mol->TesselStruct, mol, 0);
|
---|
541 | tecplot->close();
|
---|
542 | delete(tecplot);
|
---|
543 | }
|
---|
544 | if (DoRaster3DOutput) {
|
---|
545 | string OutputName(filename);
|
---|
546 | OutputName.append(Raster3DSuffix);
|
---|
547 | ofstream *rasterplot = new ofstream(OutputName.c_str());
|
---|
548 | write_raster3d_file(out, rasterplot, mol->TesselStruct, mol);
|
---|
549 | rasterplot->close();
|
---|
550 | delete(rasterplot);
|
---|
551 | }
|
---|
552 | }
|
---|
553 |
|
---|
554 |
|
---|
555 | // free reference lists
|
---|
556 | if (BoundaryFreeFlag)
|
---|
557 | delete[] (BoundaryPoints);
|
---|
558 |
|
---|
559 | cout << Verbose(1) << "End of find_convex_border" << endl;
|
---|
560 | };
|
---|
561 |
|
---|
562 |
|
---|
563 | /** Determines the volume of a cluster.
|
---|
564 | * Determines first the convex envelope, then tesselates it and calculates its volume.
|
---|
565 | * \param *out output stream for debugging
|
---|
566 | * \param *TesselStruct Tesselation filled with points, lines and triangles on boundary on return
|
---|
567 | * \param *configuration needed for path to store convex envelope file
|
---|
568 | * \return determined volume of the cluster in cubed config:GetIsAngstroem()
|
---|
569 | */
|
---|
570 | double VolumeOfConvexEnvelope(ofstream *out, class Tesselation *TesselStruct, class config *configuration)
|
---|
571 | {
|
---|
572 | bool IsAngstroem = configuration->GetIsAngstroem();
|
---|
573 | double volume = 0.;
|
---|
574 | double PyramidVolume = 0.;
|
---|
575 | double G, h;
|
---|
576 | Vector x, y;
|
---|
577 | double a, b, c;
|
---|
578 |
|
---|
579 | // 6a. Every triangle forms a pyramid with the center of gravity as its peak, sum up the volumes
|
---|
580 | *out << Verbose(1)
|
---|
581 | << "Calculating the volume of the pyramids formed out of triangles and center of gravity."
|
---|
582 | << endl;
|
---|
583 | for (TriangleMap::iterator runner = TesselStruct->TrianglesOnBoundary.begin(); runner != TesselStruct->TrianglesOnBoundary.end(); runner++)
|
---|
584 | { // go through every triangle, calculate volume of its pyramid with CoG as peak
|
---|
585 | x.CopyVector(runner->second->endpoints[0]->node->node);
|
---|
586 | x.SubtractVector(runner->second->endpoints[1]->node->node);
|
---|
587 | y.CopyVector(runner->second->endpoints[0]->node->node);
|
---|
588 | y.SubtractVector(runner->second->endpoints[2]->node->node);
|
---|
589 | a = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
|
---|
590 | b = sqrt(runner->second->endpoints[0]->node->node->DistanceSquared(runner->second->endpoints[2]->node->node));
|
---|
591 | c = sqrt(runner->second->endpoints[2]->node->node->DistanceSquared(runner->second->endpoints[1]->node->node));
|
---|
592 | G = sqrt(((a + b + c) * (a + b + c) - 2 * (a * a + b * b + c * c)) / 16.); // area of tesselated triangle
|
---|
593 | x.MakeNormalVector(runner->second->endpoints[0]->node->node, runner->second->endpoints[1]->node->node, runner->second->endpoints[2]->node->node);
|
---|
594 | x.Scale(runner->second->endpoints[1]->node->node->Projection(&x));
|
---|
595 | h = x.Norm(); // distance of CoG to triangle
|
---|
596 | PyramidVolume = (1. / 3.) * G * h; // this formula holds for _all_ pyramids (independent of n-edge base or (not) centered peak)
|
---|
597 | *out << Verbose(2) << "Area of triangle is " << G << " "
|
---|
598 | << (IsAngstroem ? "angstrom" : "atomiclength") << "^2, height is "
|
---|
599 | << h << " and the volume is " << PyramidVolume << " "
|
---|
600 | << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
|
---|
601 | volume += PyramidVolume;
|
---|
602 | }
|
---|
603 | *out << Verbose(0) << "RESULT: The summed volume is " << setprecision(10)
|
---|
604 | << volume << " " << (IsAngstroem ? "angstrom" : "atomiclength") << "^3."
|
---|
605 | << endl;
|
---|
606 |
|
---|
607 | return volume;
|
---|
608 | }
|
---|
609 | ;
|
---|
610 |
|
---|
611 | /** Creates multiples of the by \a *mol given cluster and suspends them in water with a given final density.
|
---|
612 | * We get cluster volume by VolumeOfConvexEnvelope() and its diameters by GetDiametersOfCluster()
|
---|
613 | * \param *out output stream for debugging
|
---|
614 | * \param *configuration needed for path to store convex envelope file
|
---|
615 | * \param *mol molecule structure representing the cluster
|
---|
616 | * \param ClusterVolume guesstimated cluster volume, if equal 0 we used VolumeOfConvexEnvelope() instead.
|
---|
617 | * \param celldensity desired average density in final cell
|
---|
618 | */
|
---|
619 | void
|
---|
620 | PrepareClustersinWater(ofstream *out, config *configuration, molecule *mol,
|
---|
621 | double ClusterVolume, double celldensity)
|
---|
622 | {
|
---|
623 | // transform to PAS
|
---|
624 | mol->PrincipalAxisSystem(out, true);
|
---|
625 |
|
---|
626 | // some preparations beforehand
|
---|
627 | bool IsAngstroem = configuration->GetIsAngstroem();
|
---|
628 | Boundaries *BoundaryPoints = GetBoundaryPoints(out, mol);
|
---|
629 | class Tesselation *TesselStruct = NULL;
|
---|
630 | LinkedCell LCList(mol, 10.);
|
---|
631 | Find_convex_border(out, mol, &LCList, NULL);
|
---|
632 | double clustervolume;
|
---|
633 | if (ClusterVolume == 0)
|
---|
634 | clustervolume = VolumeOfConvexEnvelope(out, TesselStruct, configuration);
|
---|
635 | else
|
---|
636 | clustervolume = ClusterVolume;
|
---|
637 | double *GreatestDiameter = GetDiametersOfCluster(out, BoundaryPoints, mol, IsAngstroem);
|
---|
638 | Vector BoxLengths;
|
---|
639 | int repetition[NDIM] =
|
---|
640 | { 1, 1, 1 };
|
---|
641 | int TotalNoClusters = 1;
|
---|
642 | for (int i = 0; i < NDIM; i++)
|
---|
643 | TotalNoClusters *= repetition[i];
|
---|
644 |
|
---|
645 | // sum up the atomic masses
|
---|
646 | double totalmass = 0.;
|
---|
647 | atom *Walker = mol->start;
|
---|
648 | while (Walker->next != mol->end)
|
---|
649 | {
|
---|
650 | Walker = Walker->next;
|
---|
651 | totalmass += Walker->type->mass;
|
---|
652 | }
|
---|
653 | *out << Verbose(0) << "RESULT: The summed mass is " << setprecision(10)
|
---|
654 | << totalmass << " atomicmassunit." << endl;
|
---|
655 |
|
---|
656 | *out << Verbose(0) << "RESULT: The average density is " << setprecision(10)
|
---|
657 | << totalmass / clustervolume << " atomicmassunit/"
|
---|
658 | << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
|
---|
659 |
|
---|
660 | // solve cubic polynomial
|
---|
661 | *out << Verbose(1) << "Solving equidistant suspension in water problem ..."
|
---|
662 | << endl;
|
---|
663 | double cellvolume;
|
---|
664 | if (IsAngstroem)
|
---|
665 | cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_A - (totalmass
|
---|
666 | / clustervolume)) / (celldensity - 1);
|
---|
667 | else
|
---|
668 | cellvolume = (TotalNoClusters * totalmass / SOLVENTDENSITY_a0 - (totalmass
|
---|
669 | / clustervolume)) / (celldensity - 1);
|
---|
670 | *out << Verbose(1) << "Cellvolume needed for a density of " << celldensity
|
---|
671 | << " g/cm^3 is " << cellvolume << " " << (IsAngstroem ? "angstrom"
|
---|
672 | : "atomiclength") << "^3." << endl;
|
---|
673 |
|
---|
674 | double minimumvolume = TotalNoClusters * (GreatestDiameter[0]
|
---|
675 | * GreatestDiameter[1] * GreatestDiameter[2]);
|
---|
676 | *out << Verbose(1)
|
---|
677 | << "Minimum volume of the convex envelope contained in a rectangular box is "
|
---|
678 | << minimumvolume << " atomicmassunit/" << (IsAngstroem ? "angstrom"
|
---|
679 | : "atomiclength") << "^3." << endl;
|
---|
680 | if (minimumvolume > cellvolume)
|
---|
681 | {
|
---|
682 | cerr << Verbose(0)
|
---|
683 | << "ERROR: the containing box already has a greater volume than the envisaged cell volume!"
|
---|
684 | << endl;
|
---|
685 | cout << Verbose(0)
|
---|
686 | << "Setting Box dimensions to minimum possible, the greatest diameters."
|
---|
687 | << endl;
|
---|
688 | for (int i = 0; i < NDIM; i++)
|
---|
689 | BoxLengths.x[i] = GreatestDiameter[i];
|
---|
690 | mol->CenterEdge(out, &BoxLengths);
|
---|
691 | }
|
---|
692 | else
|
---|
693 | {
|
---|
694 | BoxLengths.x[0] = (repetition[0] * GreatestDiameter[0] + repetition[1]
|
---|
695 | * GreatestDiameter[1] + repetition[2] * GreatestDiameter[2]);
|
---|
696 | BoxLengths.x[1] = (repetition[0] * repetition[1] * GreatestDiameter[0]
|
---|
697 | * GreatestDiameter[1] + repetition[0] * repetition[2]
|
---|
698 | * GreatestDiameter[0] * GreatestDiameter[2] + repetition[1]
|
---|
699 | * repetition[2] * GreatestDiameter[1] * GreatestDiameter[2]);
|
---|
700 | BoxLengths.x[2] = minimumvolume - cellvolume;
|
---|
701 | double x0 = 0., x1 = 0., x2 = 0.;
|
---|
702 | if (gsl_poly_solve_cubic(BoxLengths.x[0], BoxLengths.x[1],
|
---|
703 | BoxLengths.x[2], &x0, &x1, &x2) == 1) // either 1 or 3 on return
|
---|
704 | *out << Verbose(0) << "RESULT: The resulting spacing is: " << x0
|
---|
705 | << " ." << endl;
|
---|
706 | else
|
---|
707 | {
|
---|
708 | *out << Verbose(0) << "RESULT: The resulting spacings are: " << x0
|
---|
709 | << " and " << x1 << " and " << x2 << " ." << endl;
|
---|
710 | x0 = x2; // sorted in ascending order
|
---|
711 | }
|
---|
712 |
|
---|
713 | cellvolume = 1;
|
---|
714 | for (int i = 0; i < NDIM; i++)
|
---|
715 | {
|
---|
716 | BoxLengths.x[i] = repetition[i] * (x0 + GreatestDiameter[i]);
|
---|
717 | cellvolume *= BoxLengths.x[i];
|
---|
718 | }
|
---|
719 |
|
---|
720 | // set new box dimensions
|
---|
721 | *out << Verbose(0) << "Translating to box with these boundaries." << endl;
|
---|
722 | mol->SetBoxDimension(&BoxLengths);
|
---|
723 | mol->CenterInBox((ofstream *) &cout);
|
---|
724 | }
|
---|
725 | // update Box of atoms by boundary
|
---|
726 | mol->SetBoxDimension(&BoxLengths);
|
---|
727 | *out << Verbose(0) << "RESULT: The resulting cell dimensions are: "
|
---|
728 | << BoxLengths.x[0] << " and " << BoxLengths.x[1] << " and "
|
---|
729 | << BoxLengths.x[2] << " with total volume of " << cellvolume << " "
|
---|
730 | << (IsAngstroem ? "angstrom" : "atomiclength") << "^3." << endl;
|
---|
731 | }
|
---|
732 | ;
|
---|
733 |
|
---|
734 |
|
---|
735 | /** Fills the empty space of the simulation box with water/
|
---|
736 | * \param *out output stream for debugging
|
---|
737 | * \param *List list of molecules already present in box
|
---|
738 | * \param *TesselStruct contains tesselated surface
|
---|
739 | * \param *filler molecule which the box is to be filled with
|
---|
740 | * \param configuration contains box dimensions
|
---|
741 | * \param distance[NDIM] distance between filling molecules in each direction
|
---|
742 | * \param RandAtomDisplacement maximum distance for random displacement per atom
|
---|
743 | * \param RandMolDisplacement maximum distance for random displacement per filler molecule
|
---|
744 | * \param DoRandomRotation true - do random rotiations, false - don't
|
---|
745 | * \return *mol pointer to new molecule with filled atoms
|
---|
746 | */
|
---|
747 | molecule * FillBoxWithMolecule(ofstream *out, MoleculeListClass *List, molecule *filler, config &configuration, double distance[NDIM], double RandomAtomDisplacement, double RandomMolDisplacement, bool DoRandomRotation)
|
---|
748 | {
|
---|
749 | molecule *Filling = new molecule(filler->elemente);
|
---|
750 | Vector CurrentPosition;
|
---|
751 | int N[NDIM];
|
---|
752 | int n[NDIM];
|
---|
753 | double *M = filler->ReturnFullMatrixforSymmetric(filler->cell_size);
|
---|
754 | double Rotations[NDIM*NDIM];
|
---|
755 | Vector AtomTranslations;
|
---|
756 | Vector FillerTranslations;
|
---|
757 | Vector FillerDistance;
|
---|
758 | double FillIt = false;
|
---|
759 | atom *Walker = NULL;
|
---|
760 | bond *Binder = NULL;
|
---|
761 | int i;
|
---|
762 | LinkedCell *LCList[List->ListOfMolecules.size()];
|
---|
763 |
|
---|
764 | *out << Verbose(0) << "Begin of FillBoxWithMolecule" << endl;
|
---|
765 |
|
---|
766 | i=0;
|
---|
767 | for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
|
---|
768 | *out << Verbose(1) << "Pre-creating linked cell lists for molecule " << *ListRunner << "." << endl;
|
---|
769 | LCList[i] = new LinkedCell((*ListRunner), 5.); // get linked cell list
|
---|
770 | if ((*ListRunner)->TesselStruct == NULL) {
|
---|
771 | *out << Verbose(1) << "Pre-creating tesselation for molecule " << *ListRunner << "." << endl;
|
---|
772 | Find_non_convex_border((ofstream *)&cout, (*ListRunner), LCList[i], NULL, 5.);
|
---|
773 | }
|
---|
774 | i++;
|
---|
775 | }
|
---|
776 |
|
---|
777 | // Center filler at origin
|
---|
778 | filler->CenterOrigin(out);
|
---|
779 | filler->Center.Zero();
|
---|
780 |
|
---|
781 | filler->CountAtoms(out);
|
---|
782 | atom * CopyAtoms[filler->AtomCount];
|
---|
783 | int nr = 0;
|
---|
784 |
|
---|
785 | // calculate filler grid in [0,1]^3
|
---|
786 | FillerDistance.Init(distance[0], distance[1], distance[2]);
|
---|
787 | FillerDistance.InverseMatrixMultiplication(M);
|
---|
788 | *out << Verbose(1) << "INFO: Grid steps are ";
|
---|
789 | for(int i=0;i<NDIM;i++) {
|
---|
790 | N[i] = (int) ceil(1./FillerDistance.x[i]);
|
---|
791 | *out << N[i];
|
---|
792 | if (i != NDIM-1)
|
---|
793 | *out<< ", ";
|
---|
794 | else
|
---|
795 | *out << "." << endl;
|
---|
796 | }
|
---|
797 |
|
---|
798 | // go over [0,1]^3 filler grid
|
---|
799 | for (n[0] = 0; n[0] < N[0]; n[0]++)
|
---|
800 | for (n[1] = 0; n[1] < N[1]; n[1]++)
|
---|
801 | for (n[2] = 0; n[2] < N[2]; n[2]++) {
|
---|
802 | // calculate position of current grid vector in untransformed box
|
---|
803 | CurrentPosition.Init((double)n[0]/(double)N[0], (double)n[1]/(double)N[1], (double)n[2]/(double)N[2]);
|
---|
804 | CurrentPosition.MatrixMultiplication(M);
|
---|
805 | *out << Verbose(2) << "INFO: Current Position is " << CurrentPosition << "." << endl;
|
---|
806 | // Check whether point is in- or outside
|
---|
807 | FillIt = true;
|
---|
808 | i=0;
|
---|
809 | for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) {
|
---|
810 | // get linked cell list
|
---|
811 | if ((*ListRunner)->TesselStruct == NULL) {
|
---|
812 | *out << Verbose(1) << "ERROR: TesselStruct of " << (*ListRunner) << " is NULL. Didn't we pre-create it?" << endl;
|
---|
813 | FillIt = false;
|
---|
814 | } else
|
---|
815 | FillIt = FillIt && (!(*ListRunner)->TesselStruct->IsInnerPoint(out, CurrentPosition, LCList[i++]));
|
---|
816 | }
|
---|
817 |
|
---|
818 | if (FillIt) {
|
---|
819 | // fill in Filler
|
---|
820 | *out << Verbose(2) << "Space at " << CurrentPosition << " is unoccupied by any molecule, filling in." << endl;
|
---|
821 |
|
---|
822 | // create molecule random translation vector ...
|
---|
823 | for (int i=0;i<NDIM;i++)
|
---|
824 | FillerTranslations.x[i] = RandomMolDisplacement*(rand()/(RAND_MAX/2.) - 1.);
|
---|
825 | *out << Verbose(3) << "INFO: Translating this filler by " << FillerTranslations << "." << endl;
|
---|
826 |
|
---|
827 | // go through all atoms
|
---|
828 | nr=0;
|
---|
829 | Walker = filler->start;
|
---|
830 | while (Walker->next != filler->end) {
|
---|
831 | Walker = Walker->next;
|
---|
832 | // copy atom ...
|
---|
833 | CopyAtoms[Walker->nr] = new atom(Walker);
|
---|
834 |
|
---|
835 | // create atomic random translation vector ...
|
---|
836 | for (int i=0;i<NDIM;i++)
|
---|
837 | AtomTranslations.x[i] = RandomAtomDisplacement*(rand()/(RAND_MAX/2.) - 1.);
|
---|
838 |
|
---|
839 | // ... and rotation matrix
|
---|
840 | if (DoRandomRotation) {
|
---|
841 | double phi[NDIM];
|
---|
842 | for (int i=0;i<NDIM;i++) {
|
---|
843 | phi[i] = rand()/(RAND_MAX/(2.*M_PI));
|
---|
844 | }
|
---|
845 |
|
---|
846 | Rotations[0] = cos(phi[0]) *cos(phi[2]) + (sin(phi[0])*sin(phi[1])*sin(phi[2]));
|
---|
847 | Rotations[3] = sin(phi[0]) *cos(phi[2]) - (cos(phi[0])*sin(phi[1])*sin(phi[2]));
|
---|
848 | Rotations[6] = cos(phi[1])*sin(phi[2]) ;
|
---|
849 | Rotations[1] = - sin(phi[0])*cos(phi[1]) ;
|
---|
850 | Rotations[4] = cos(phi[0])*cos(phi[1]) ;
|
---|
851 | Rotations[7] = sin(phi[1]) ;
|
---|
852 | Rotations[3] = - cos(phi[0]) *sin(phi[2]) + (sin(phi[0])*sin(phi[1])*cos(phi[2]));
|
---|
853 | Rotations[5] = - sin(phi[0]) *sin(phi[2]) - (cos(phi[0])*sin(phi[1])*cos(phi[2]));
|
---|
854 | Rotations[8] = cos(phi[1])*cos(phi[2]) ;
|
---|
855 | }
|
---|
856 |
|
---|
857 | // ... and put at new position
|
---|
858 | if (DoRandomRotation)
|
---|
859 | CopyAtoms[Walker->nr]->x.MatrixMultiplication(Rotations);
|
---|
860 | CopyAtoms[Walker->nr]->x.AddVector(&AtomTranslations);
|
---|
861 | CopyAtoms[Walker->nr]->x.AddVector(&FillerTranslations);
|
---|
862 | CopyAtoms[Walker->nr]->x.AddVector(&CurrentPosition);
|
---|
863 |
|
---|
864 | // insert into Filling
|
---|
865 |
|
---|
866 | // FIXME: gives completely different results if CopyAtoms[..] used instead of Walker, why???
|
---|
867 | *out << Verbose(4) << "Filling atom " << *Walker << ", translated to " << AtomTranslations << ", at final position is " << (CopyAtoms[Walker->nr]->x) << "." << endl;
|
---|
868 | Filling->AddAtom(CopyAtoms[Walker->nr]);
|
---|
869 | }
|
---|
870 |
|
---|
871 | // go through all bonds and add as well
|
---|
872 | Binder = filler->first;
|
---|
873 | while(Binder->next != filler->last) {
|
---|
874 | Binder = Binder->next;
|
---|
875 | *out << Verbose(3) << "Adding Bond between " << *CopyAtoms[Binder->leftatom->nr] << " and " << *CopyAtoms[Binder->rightatom->nr]<< "." << endl;
|
---|
876 | Filling->AddBond(CopyAtoms[Binder->leftatom->nr], CopyAtoms[Binder->rightatom->nr], Binder->BondDegree);
|
---|
877 | }
|
---|
878 | } else {
|
---|
879 | // leave empty
|
---|
880 | *out << Verbose(2) << "Space at " << CurrentPosition << " is occupied." << endl;
|
---|
881 | }
|
---|
882 | }
|
---|
883 | *out << Verbose(0) << "End of FillBoxWithMolecule" << endl;
|
---|
884 |
|
---|
885 | return Filling;
|
---|
886 | };
|
---|
887 |
|
---|
888 |
|
---|
889 | /** Tesselates the non convex boundary by rolling a virtual sphere along the surface of the molecule.
|
---|
890 | * \param *out output stream for debugging
|
---|
891 | * \param *mol molecule structure with Atom's and Bond's
|
---|
892 | * \param *Tess Tesselation filled with points, lines and triangles on boundary on return
|
---|
893 | * \param *LCList atoms in LinkedCell list
|
---|
894 | * \param *filename filename prefix for output of vertex data
|
---|
895 | * \para RADIUS radius of the virtual sphere
|
---|
896 | */
|
---|
897 | void Find_non_convex_border(ofstream *out, molecule* mol, class LinkedCell *LCList, const char *filename, const double RADIUS)
|
---|
898 | {
|
---|
899 | int N = 0;
|
---|
900 | bool freeLC = false;
|
---|
901 | ofstream *tempstream = NULL;
|
---|
902 | char NumberName[255];
|
---|
903 | int TriangleFilesWritten = 0;
|
---|
904 |
|
---|
905 | *out << Verbose(1) << "Entering search for non convex hull. " << endl;
|
---|
906 | if (mol->TesselStruct == NULL) {
|
---|
907 | *out << Verbose(1) << "Allocating Tesselation struct ..." << endl;
|
---|
908 | mol->TesselStruct = new Tesselation;
|
---|
909 | } else {
|
---|
910 | delete(mol->TesselStruct);
|
---|
911 | *out << Verbose(1) << "Re-Allocating Tesselation struct ..." << endl;
|
---|
912 | mol->TesselStruct = new Tesselation;
|
---|
913 | }
|
---|
914 | LineMap::iterator baseline;
|
---|
915 | LineMap::iterator testline;
|
---|
916 | *out << Verbose(0) << "Begin of Find_non_convex_border\n";
|
---|
917 | bool flag = false; // marks whether we went once through all baselines without finding any without two triangles
|
---|
918 | bool failflag = false;
|
---|
919 |
|
---|
920 | if (LCList == NULL) {
|
---|
921 | LCList = new LinkedCell(mol, 2.*RADIUS);
|
---|
922 | freeLC = true;
|
---|
923 | }
|
---|
924 |
|
---|
925 | mol->TesselStruct->Find_starting_triangle(out, RADIUS, LCList);
|
---|
926 |
|
---|
927 | baseline = mol->TesselStruct->LinesOnBoundary.begin();
|
---|
928 | while ((baseline != mol->TesselStruct->LinesOnBoundary.end()) || (flag)) {
|
---|
929 | if (baseline->second->TrianglesCount == 1) {
|
---|
930 | failflag = mol->TesselStruct->Find_next_suitable_triangle(out, *(baseline->second), *(((baseline->second->triangles.begin()))->second), RADIUS, N, LCList); //the line is there, so there is a triangle, but only one.
|
---|
931 | flag = flag || failflag;
|
---|
932 | if (!failflag)
|
---|
933 | cerr << "WARNING: Find_next_suitable_triangle failed." << endl;
|
---|
934 | // write temporary envelope
|
---|
935 | if ((DoSingleStepOutput && (mol->TesselStruct->TrianglesOnBoundaryCount % SingleStepWidth == 0))) { // if we have a new triangle and want to output each new triangle configuration
|
---|
936 | TriangleMap::iterator runner = mol->TesselStruct->TrianglesOnBoundary.end();
|
---|
937 | runner--;
|
---|
938 | class BoundaryTriangleSet *triangle = runner->second;
|
---|
939 | if (triangle != NULL) {
|
---|
940 | sprintf(NumberName, "-%04d-%s_%s_%s", TriangleFilesWritten, triangle->endpoints[0]->node->Name, triangle->endpoints[1]->node->Name, triangle->endpoints[2]->node->Name);
|
---|
941 | if (DoTecplotOutput) {
|
---|
942 | string NameofTempFile(filename);
|
---|
943 | NameofTempFile.append(NumberName);
|
---|
944 | for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
|
---|
945 | NameofTempFile.erase(npos, 1);
|
---|
946 | NameofTempFile.append(TecplotSuffix);
|
---|
947 | *out << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
|
---|
948 | tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
|
---|
949 | write_tecplot_file(out, tempstream, mol->TesselStruct, mol, TriangleFilesWritten);
|
---|
950 | tempstream->close();
|
---|
951 | tempstream->flush();
|
---|
952 | delete(tempstream);
|
---|
953 | }
|
---|
954 |
|
---|
955 | if (DoRaster3DOutput) {
|
---|
956 | string NameofTempFile(filename);
|
---|
957 | NameofTempFile.append(NumberName);
|
---|
958 | for(size_t npos = NameofTempFile.find_first_of(' '); npos != string::npos; npos = NameofTempFile.find(' ', npos))
|
---|
959 | NameofTempFile.erase(npos, 1);
|
---|
960 | NameofTempFile.append(Raster3DSuffix);
|
---|
961 | *out << Verbose(1) << "Writing temporary non convex hull to file " << NameofTempFile << ".\n";
|
---|
962 | tempstream = new ofstream(NameofTempFile.c_str(), ios::trunc);
|
---|
963 | write_raster3d_file(out, tempstream, mol->TesselStruct, mol);
|
---|
964 | // // include the current position of the virtual sphere in the temporary raster3d file
|
---|
965 | // // make the circumsphere's center absolute again
|
---|
966 | // helper.CopyVector(BaseRay->endpoints[0]->node->node);
|
---|
967 | // helper.AddVector(BaseRay->endpoints[1]->node->node);
|
---|
968 | // helper.Scale(0.5);
|
---|
969 | // (*it)->OptCenter.AddVector(&helper);
|
---|
970 | // Vector *center = mol->DetermineCenterOfAll(out);
|
---|
971 | // (*it)->OptCenter.SubtractVector(center);
|
---|
972 | // delete(center);
|
---|
973 | // // and add to file plus translucency object
|
---|
974 | // *tempstream << "# current virtual sphere\n";
|
---|
975 | // *tempstream << "8\n 25.0 0.6 -1.0 -1.0 -1.0 0.2 0 0 0 0\n";
|
---|
976 | // *tempstream << "2\n " << (*it)->OptCenter.x[0] << " "
|
---|
977 | // << (*it)->OptCenter.x[1] << " " << (*it)->OptCenter.x[2]
|
---|
978 | // << "\t" << RADIUS << "\t1 0 0\n";
|
---|
979 | // *tempstream << "9\n terminating special property\n";
|
---|
980 | tempstream->close();
|
---|
981 | tempstream->flush();
|
---|
982 | delete(tempstream);
|
---|
983 | }
|
---|
984 | }
|
---|
985 | if (DoTecplotOutput || DoRaster3DOutput)
|
---|
986 | TriangleFilesWritten++;
|
---|
987 | }
|
---|
988 | } else {
|
---|
989 | //cout << Verbose(1) << "Line " << *baseline->second << " has " << baseline->second->TrianglesCount << " triangles adjacent" << endl;
|
---|
990 | if (baseline->second->TrianglesCount != 2)
|
---|
991 | *out << Verbose(1) << "ERROR: TESSELATION FINISHED WITH INVALID TRIANGLE COUNT!" << endl;
|
---|
992 | }
|
---|
993 |
|
---|
994 | N++;
|
---|
995 | baseline++;
|
---|
996 | if ((baseline == mol->TesselStruct->LinesOnBoundary.end()) && (flag)) {
|
---|
997 | baseline = mol->TesselStruct->LinesOnBoundary.begin(); // restart if we reach end due to newly inserted lines
|
---|
998 | flag = false;
|
---|
999 | }
|
---|
1000 | }
|
---|
1001 |
|
---|
1002 | // write final envelope
|
---|
1003 | if (filename != 0) {
|
---|
1004 | *out << Verbose(1) << "Writing final tecplot file\n";
|
---|
1005 | if (DoTecplotOutput) {
|
---|
1006 | string OutputName(filename);
|
---|
1007 | OutputName.append(TecplotSuffix);
|
---|
1008 | ofstream *tecplot = new ofstream(OutputName.c_str());
|
---|
1009 | write_tecplot_file(out, tecplot, mol->TesselStruct, mol, -1);
|
---|
1010 | tecplot->close();
|
---|
1011 | delete(tecplot);
|
---|
1012 | }
|
---|
1013 | if (DoRaster3DOutput) {
|
---|
1014 | string OutputName(filename);
|
---|
1015 | OutputName.append(Raster3DSuffix);
|
---|
1016 | ofstream *raster = new ofstream(OutputName.c_str());
|
---|
1017 | write_raster3d_file(out, raster, mol->TesselStruct, mol);
|
---|
1018 | raster->close();
|
---|
1019 | delete(raster);
|
---|
1020 | }
|
---|
1021 | } else {
|
---|
1022 | cerr << "ERROR: Could definitively not find all necessary triangles!" << endl;
|
---|
1023 | }
|
---|
1024 |
|
---|
1025 | cout << Verbose(2) << "Check: List of Baselines with not two connected triangles:" << endl;
|
---|
1026 | int counter = 0;
|
---|
1027 | for (testline = mol->TesselStruct->LinesOnBoundary.begin(); testline != mol->TesselStruct->LinesOnBoundary.end(); testline++) {
|
---|
1028 | if (testline->second->TrianglesCount != 2) {
|
---|
1029 | cout << Verbose(2) << *testline->second << "\t" << testline->second->TrianglesCount << endl;
|
---|
1030 | counter++;
|
---|
1031 | }
|
---|
1032 | }
|
---|
1033 | if (counter == 0)
|
---|
1034 | *out << Verbose(2) << "None." << endl;
|
---|
1035 |
|
---|
1036 | // // Tests the IsInnerAtom() function.
|
---|
1037 | // Vector x (0, 0, 0);
|
---|
1038 | // *out << Verbose(0) << "Point to check: " << x << endl;
|
---|
1039 | // *out << Verbose(0) << "Check: IsInnerPoint() returns " << mol->TesselStruct->IsInnerPoint(out, x, LCList)
|
---|
1040 | // << "for vector " << x << "." << endl;
|
---|
1041 | // TesselPoint* a = mol->TesselStruct->PointsOnBoundary.begin()->second->node;
|
---|
1042 | // *out << Verbose(0) << "Point to check: " << *a << " (on boundary)." << endl;
|
---|
1043 | // *out << Verbose(0) << "Check: IsInnerAtom() returns " << mol->TesselStruct->IsInnerPoint(out, a, LCList)
|
---|
1044 | // << "for atom " << a << " (on boundary)." << endl;
|
---|
1045 | // LinkedNodes *List = NULL;
|
---|
1046 | // for (int i=0;i<NDIM;i++) { // each axis
|
---|
1047 | // LCList->n[i] = LCList->N[i]-1; // current axis is topmost cell
|
---|
1048 | // for (LCList->n[(i+1)%NDIM]=0;LCList->n[(i+1)%NDIM]<LCList->N[(i+1)%NDIM];LCList->n[(i+1)%NDIM]++)
|
---|
1049 | // for (LCList->n[(i+2)%NDIM]=0;LCList->n[(i+2)%NDIM]<LCList->N[(i+2)%NDIM];LCList->n[(i+2)%NDIM]++) {
|
---|
1050 | // List = LCList->GetCurrentCell();
|
---|
1051 | // //cout << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << "." << endl;
|
---|
1052 | // if (List != NULL) {
|
---|
1053 | // for (LinkedNodes::iterator Runner = List->begin();Runner != List->end();Runner++) {
|
---|
1054 | // if (mol->TesselStruct->PointsOnBoundary.find((*Runner)->nr) == mol->TesselStruct->PointsOnBoundary.end()) {
|
---|
1055 | // a = *Runner;
|
---|
1056 | // i=3;
|
---|
1057 | // for (int j=0;j<NDIM;j++)
|
---|
1058 | // LCList->n[j] = LCList->N[j];
|
---|
1059 | // break;
|
---|
1060 | // }
|
---|
1061 | // }
|
---|
1062 | // }
|
---|
1063 | // }
|
---|
1064 | // }
|
---|
1065 | // *out << Verbose(0) << "Check: IsInnerPoint() returns " << mol->TesselStruct->IsInnerPoint(out, a, LCList)
|
---|
1066 | // << "for atom " << a << " (inside)." << endl;
|
---|
1067 |
|
---|
1068 |
|
---|
1069 | if (freeLC)
|
---|
1070 | delete(LCList);
|
---|
1071 | *out << Verbose(0) << "End of Find_non_convex_border\n";
|
---|
1072 | };
|
---|
1073 |
|
---|
1074 | /** Finds a hole of sufficient size in \a this molecule to embed \a *srcmol into it.
|
---|
1075 | * \param *out output stream for debugging
|
---|
1076 | * \param *srcmol molecule to embed into
|
---|
1077 | * \return *Vector new center of \a *srcmol for embedding relative to \a this
|
---|
1078 | */
|
---|
1079 | Vector* molecule::FindEmbeddingHole(ofstream *out, molecule *srcmol)
|
---|
1080 | {
|
---|
1081 | Vector *Center = new Vector;
|
---|
1082 | Center->Zero();
|
---|
1083 | // calculate volume/shape of \a *srcmol
|
---|
1084 |
|
---|
1085 | // find embedding holes
|
---|
1086 |
|
---|
1087 | // if more than one, let user choose
|
---|
1088 |
|
---|
1089 | // return embedding center
|
---|
1090 | return Center;
|
---|
1091 | };
|
---|
1092 |
|
---|