source: src/ellipsoid.cpp@ 28c351

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

Huge change: Log() << Verbose(.) --> DoLog(.) && (Log() << Verbose(.) << ...);

Most of the files are affected, but this is necessary as if DoLog() says verbosity is not enough, all the stream operators won"t get executed which saves substantial amount of computation time.

Signed-off-by: Frederik Heber <heber@…>

  • Property mode set to 100644
File size: 17.0 KB
Line 
1/*
2 * ellipsoid.cpp
3 *
4 * Created on: Jan 20, 2009
5 * Author: heber
6 */
7
8#include <gsl/gsl_multimin.h>
9#include <gsl/gsl_vector.h>
10
11#include <iomanip>
12
13#include <set>
14
15#include "boundary.hpp"
16#include "ellipsoid.hpp"
17#include "linkedcell.hpp"
18#include "log.hpp"
19#include "tesselation.hpp"
20#include "vector.hpp"
21#include "verbose.hpp"
22
23/** Determines squared distance for a given point \a x to surface of ellipsoid.
24 * \param x given point
25 * \param EllipsoidCenter center of ellipsoid
26 * \param EllipsoidLength[3] three lengths of half axis of ellipsoid
27 * \param EllipsoidAngle[3] three rotation angles of ellipsoid
28 * \return squared distance from point to surface
29 */
30double SquaredDistanceToEllipsoid(Vector &x, Vector &EllipsoidCenter, double *EllipsoidLength, double *EllipsoidAngle)
31{
32 Vector helper, RefPoint;
33 double distance = -1.;
34 double Matrix[NDIM*NDIM];
35 double InverseLength[3];
36 double psi,theta,phi; // euler angles in ZX'Z'' convention
37
38 //Log() << Verbose(3) << "Begin of SquaredDistanceToEllipsoid" << endl;
39
40 for(int i=0;i<3;i++)
41 InverseLength[i] = 1./EllipsoidLength[i];
42
43 // 1. translate coordinate system so that ellipsoid center is in origin
44 helper.CopyVector(&x);
45 helper.SubtractVector(&EllipsoidCenter);
46 RefPoint.CopyVector(&helper);
47 //Log() << Verbose(4) << "Translated given point is at " << RefPoint << "." << endl;
48
49 // 2. transform coordinate system by inverse of rotation matrix and of diagonal matrix
50 psi = EllipsoidAngle[0];
51 theta = EllipsoidAngle[1];
52 phi = EllipsoidAngle[2];
53 Matrix[0] = cos(psi)*cos(phi) - sin(psi)*cos(theta)*sin(phi);
54 Matrix[1] = -cos(psi)*sin(phi) - sin(psi)*cos(theta)*cos(phi);
55 Matrix[2] = sin(psi)*sin(theta);
56 Matrix[3] = sin(psi)*cos(phi) + cos(psi)*cos(theta)*sin(phi);
57 Matrix[4] = cos(psi)*cos(theta)*cos(phi) - sin(psi)*sin(phi);
58 Matrix[5] = -cos(psi)*sin(theta);
59 Matrix[6] = sin(theta)*sin(phi);
60 Matrix[7] = sin(theta)*cos(phi);
61 Matrix[8] = cos(theta);
62 helper.MatrixMultiplication(Matrix);
63 helper.Scale(InverseLength);
64 //Log() << Verbose(4) << "Transformed RefPoint is at " << helper << "." << endl;
65
66 // 3. construct intersection point with unit sphere and ray between origin and x
67 helper.Normalize(); // is simply normalizes vector in distance direction
68 //Log() << Verbose(4) << "Transformed intersection is at " << helper << "." << endl;
69
70 // 4. transform back the constructed intersection point
71 psi = -EllipsoidAngle[0];
72 theta = -EllipsoidAngle[1];
73 phi = -EllipsoidAngle[2];
74 helper.Scale(EllipsoidLength);
75 Matrix[0] = cos(psi)*cos(phi) - sin(psi)*cos(theta)*sin(phi);
76 Matrix[1] = -cos(psi)*sin(phi) - sin(psi)*cos(theta)*cos(phi);
77 Matrix[2] = sin(psi)*sin(theta);
78 Matrix[3] = sin(psi)*cos(phi) + cos(psi)*cos(theta)*sin(phi);
79 Matrix[4] = cos(psi)*cos(theta)*cos(phi) - sin(psi)*sin(phi);
80 Matrix[5] = -cos(psi)*sin(theta);
81 Matrix[6] = sin(theta)*sin(phi);
82 Matrix[7] = sin(theta)*cos(phi);
83 Matrix[8] = cos(theta);
84 helper.MatrixMultiplication(Matrix);
85 //Log() << Verbose(4) << "Intersection is at " << helper << "." << endl;
86
87 // 5. determine distance between backtransformed point and x
88 distance = RefPoint.DistanceSquared(&helper);
89 //Log() << Verbose(4) << "Squared distance between intersection and RefPoint is " << distance << "." << endl;
90
91 return distance;
92 //Log() << Verbose(3) << "End of SquaredDistanceToEllipsoid" << endl;
93};
94
95/** structure for ellipsoid minimisation containing points to fit to.
96 */
97struct EllipsoidMinimisation {
98 int N; //!< dimension of vector set
99 Vector *x; //!< array of vectors
100};
101
102/** Sum of squared distance to ellipsoid to be minimised.
103 * \param *x parameters for the ellipsoid
104 * \param *params EllipsoidMinimisation with set of data points to minimise distance to and dimension
105 * \return sum of squared distance, \sa SquaredDistanceToEllipsoid()
106 */
107double SumSquaredDistance (const gsl_vector * x, void * params)
108{
109 Vector *set= ((struct EllipsoidMinimisation *)params)->x;
110 int N = ((struct EllipsoidMinimisation *)params)->N;
111 double SumDistance = 0.;
112 double distance;
113 Vector Center;
114 double EllipsoidLength[3], EllipsoidAngle[3];
115
116 // put parameters into suitable ellipsoid form
117 for (int i=0;i<3;i++) {
118 Center.x[i] = gsl_vector_get(x, i+0);
119 EllipsoidLength[i] = gsl_vector_get(x, i+3);
120 EllipsoidAngle[i] = gsl_vector_get(x, i+6);
121 }
122
123 // go through all points and sum distance
124 for (int i=0;i<N;i++) {
125 distance = SquaredDistanceToEllipsoid(set[i], Center, EllipsoidLength, EllipsoidAngle);
126 if (!isnan(distance)) {
127 SumDistance += distance;
128 } else {
129 SumDistance = GSL_NAN;
130 break;
131 }
132 }
133
134 //Log() << Verbose(0) << "Current summed distance is " << SumDistance << "." << endl;
135 return SumDistance;
136};
137
138/** Finds best fitting ellipsoid parameter set in Least square sense for a given point set.
139 * \param *out output stream for debugging
140 * \param *set given point set
141 * \param N number of points in set
142 * \param EllipsoidParamter[3] three parameters in ellipsoid equation
143 * \return true - fit successful, false - fit impossible
144 */
145bool FitPointSetToEllipsoid(Vector *set, int N, Vector *EllipsoidCenter, double *EllipsoidLength, double *EllipsoidAngle)
146{
147 int status = GSL_SUCCESS;
148 DoLog(2) && (Log() << Verbose(2) << "Begin of FitPointSetToEllipsoid " << endl);
149 if (N >= 3) { // check that enough points are given (9 d.o.f.)
150 struct EllipsoidMinimisation par;
151 const gsl_multimin_fminimizer_type *T = gsl_multimin_fminimizer_nmsimplex;
152 gsl_multimin_fminimizer *s = NULL;
153 gsl_vector *ss, *x;
154 gsl_multimin_function minex_func;
155
156 size_t iter = 0;
157 double size;
158
159 /* Starting point */
160 x = gsl_vector_alloc (9);
161 for (int i=0;i<3;i++) {
162 gsl_vector_set (x, i+0, EllipsoidCenter->x[i]);
163 gsl_vector_set (x, i+3, EllipsoidLength[i]);
164 gsl_vector_set (x, i+6, EllipsoidAngle[i]);
165 }
166 par.x = set;
167 par.N = N;
168
169 /* Set initial step sizes */
170 ss = gsl_vector_alloc (9);
171 for (int i=0;i<3;i++) {
172 gsl_vector_set (ss, i+0, 0.1);
173 gsl_vector_set (ss, i+3, 1.0);
174 gsl_vector_set (ss, i+6, M_PI/20.);
175 }
176
177 /* Initialize method and iterate */
178 minex_func.n = 9;
179 minex_func.f = &SumSquaredDistance;
180 minex_func.params = (void *)&par;
181
182 s = gsl_multimin_fminimizer_alloc (T, 9);
183 gsl_multimin_fminimizer_set (s, &minex_func, x, ss);
184
185 do {
186 iter++;
187 status = gsl_multimin_fminimizer_iterate(s);
188
189 if (status)
190 break;
191
192 size = gsl_multimin_fminimizer_size (s);
193 status = gsl_multimin_test_size (size, 1e-2);
194
195 if (status == GSL_SUCCESS) {
196 for (int i=0;i<3;i++) {
197 EllipsoidCenter->x[i] = gsl_vector_get (s->x,i+0);
198 EllipsoidLength[i] = gsl_vector_get (s->x, i+3);
199 EllipsoidAngle[i] = gsl_vector_get (s->x, i+6);
200 }
201 DoLog(4) && (Log() << Verbose(4) << setprecision(3) << "Converged fit at: " << *EllipsoidCenter << ", lengths " << EllipsoidLength[0] << ", " << EllipsoidLength[1] << ", " << EllipsoidLength[2] << ", angles " << EllipsoidAngle[0] << ", " << EllipsoidAngle[1] << ", " << EllipsoidAngle[2] << " with summed distance " << s->fval << "." << endl);
202 }
203
204 } while (status == GSL_CONTINUE && iter < 1000);
205
206 gsl_vector_free(x);
207 gsl_vector_free(ss);
208 gsl_multimin_fminimizer_free (s);
209
210 } else {
211 DoLog(3) && (Log() << Verbose(3) << "Not enough points provided for fit to ellipsoid." << endl);
212 return false;
213 }
214 DoLog(2) && (Log() << Verbose(2) << "End of FitPointSetToEllipsoid" << endl);
215 if (status == GSL_SUCCESS)
216 return true;
217 else
218 return false;
219};
220
221/** Picks a number of random points from a LC neighbourhood as a fitting set.
222 * \param *out output stream for debugging
223 * \param *T Tesselation containing boundary points
224 * \param *LC linked cell list of all atoms
225 * \param *&x random point set on return (not allocated!)
226 * \param PointsToPick number of points in set to pick
227 */
228void PickRandomNeighbouredPointSet(class Tesselation *T, class LinkedCell *LC, Vector *&x, size_t PointsToPick)
229{
230 size_t PointsLeft = 0;
231 size_t PointsPicked = 0;
232 int Nlower[NDIM], Nupper[NDIM];
233 set<int> PickedAtomNrs; // ordered list of picked atoms
234 set<int>::iterator current;
235 int index;
236 TesselPoint *Candidate = NULL;
237 DoLog(2) && (Log() << Verbose(2) << "Begin of PickRandomPointSet" << endl);
238
239 // allocate array
240 if (x == NULL) {
241 x = new Vector[PointsToPick];
242 } else {
243 DoeLog(2) && (eLog()<< Verbose(2) << "Given pointer to vector array seems already allocated." << endl);
244 }
245
246 do {
247 for(int i=0;i<NDIM;i++) // pick three random indices
248 LC->n[i] = (rand() % LC->N[i]);
249 DoLog(2) && (Log() << Verbose(2) << "INFO: Center cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " ... ");
250 // get random cell
251 const LinkedCell::LinkedNodes *List = LC->GetCurrentCell();
252 if (List == NULL) { // set index to it
253 continue;
254 }
255 DoLog(2) && (Log() << Verbose(2) << "with No. " << LC->index << "." << endl);
256
257 DoLog(2) && (Log() << Verbose(2) << "LC Intervals:");
258 for (int i=0;i<NDIM;i++) {
259 Nlower[i] = ((LC->n[i]-1) >= 0) ? LC->n[i]-1 : 0;
260 Nupper[i] = ((LC->n[i]+1) < LC->N[i]) ? LC->n[i]+1 : LC->N[i]-1;
261 DoLog(0) && (Log() << Verbose(0) << " [" << Nlower[i] << "," << Nupper[i] << "] ");
262 }
263 DoLog(0) && (Log() << Verbose(0) << endl);
264
265 // count whether there are sufficient atoms in this cell+neighbors
266 PointsLeft=0;
267 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
268 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
269 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
270 const LinkedCell::LinkedNodes *List = LC->GetCurrentCell();
271 PointsLeft += List->size();
272 }
273 DoLog(2) && (Log() << Verbose(2) << "There are " << PointsLeft << " atoms in this neighbourhood." << endl);
274 if (PointsLeft < PointsToPick) { // ensure that we can pick enough points in its neighbourhood at all.
275 continue;
276 }
277
278 // pre-pick a fixed number of atoms
279 PickedAtomNrs.clear();
280 do {
281 index = (rand() % PointsLeft);
282 current = PickedAtomNrs.find(index); // not present?
283 if (current == PickedAtomNrs.end()) {
284 //Log() << Verbose(2) << "Picking atom nr. " << index << "." << endl;
285 PickedAtomNrs.insert(index);
286 }
287 } while (PickedAtomNrs.size() < PointsToPick);
288
289 index = 0; // now go through all and pick those whose from PickedAtomsNr
290 PointsPicked=0;
291 current = PickedAtomNrs.begin();
292 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++)
293 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++)
294 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) {
295 const LinkedCell::LinkedNodes *List = LC->GetCurrentCell();
296// Log() << Verbose(2) << "Current cell is " << LC->n[0] << ", " << LC->n[1] << ", " << LC->n[2] << " with No. " << LC->index << " containing " << List->size() << " points." << endl;
297 if (List != NULL) {
298// if (List->begin() != List->end())
299// Log() << Verbose(2) << "Going through candidates ... " << endl;
300// else
301// Log() << Verbose(2) << "Cell is empty ... " << endl;
302 for (LinkedCell::LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) {
303 if ((current != PickedAtomNrs.end()) && (*current == index)) {
304 Candidate = (*Runner);
305 DoLog(2) && (Log() << Verbose(2) << "Current picked node is " << **Runner << " with index " << index << "." << endl);
306 x[PointsPicked++].CopyVector(Candidate->node); // we have one more atom picked
307 current++; // next pre-picked atom
308 }
309 index++; // next atom nr.
310 }
311// } else {
312// Log() << Verbose(2) << "List for this index not allocated!" << endl;
313 }
314 }
315 DoLog(2) && (Log() << Verbose(2) << "The following points were picked: " << endl);
316 for (size_t i=0;i<PointsPicked;i++)
317 DoLog(2) && (Log() << Verbose(2) << x[i] << endl);
318 if (PointsPicked == PointsToPick) // break out of loop if we have all
319 break;
320 } while(1);
321
322 DoLog(2) && (Log() << Verbose(2) << "End of PickRandomPointSet" << endl);
323};
324
325/** Picks a number of random points from a set of boundary points as a fitting set.
326 * \param *out output stream for debugging
327 * \param *T Tesselation containing boundary points
328 * \param *&x random point set on return (not allocated!)
329 * \param PointsToPick number of points in set to pick
330 */
331void PickRandomPointSet(class Tesselation *T, Vector *&x, size_t PointsToPick)
332{
333 size_t PointsLeft = (size_t) T->PointsOnBoundaryCount;
334 size_t PointsPicked = 0;
335 double value, threshold;
336 PointMap *List = &T->PointsOnBoundary;
337 DoLog(2) && (Log() << Verbose(2) << "Begin of PickRandomPointSet" << endl);
338
339 // allocate array
340 if (x == NULL) {
341 x = new Vector[PointsToPick];
342 } else {
343 DoeLog(2) && (eLog()<< Verbose(2) << "Given pointer to vector array seems already allocated." << endl);
344 }
345
346 if (List != NULL)
347 for (PointMap::iterator Runner = List->begin(); Runner != List->end(); Runner++) {
348 threshold = 1. - (double)(PointsToPick - PointsPicked)/(double)PointsLeft;
349 value = (double)rand()/(double)RAND_MAX;
350 //Log() << Verbose(3) << "Current node is " << *Runner->second->node << " with " << value << " ... " << threshold << ": ";
351 if (value > threshold) {
352 x[PointsPicked].CopyVector(Runner->second->node->node);
353 PointsPicked++;
354 //Log() << Verbose(0) << "IN." << endl;
355 } else {
356 //Log() << Verbose(0) << "OUT." << endl;
357 }
358 PointsLeft--;
359 }
360 DoLog(2) && (Log() << Verbose(2) << "The following points were picked: " << endl);
361 for (size_t i=0;i<PointsPicked;i++)
362 DoLog(3) && (Log() << Verbose(3) << x[i] << endl);
363
364 DoLog(2) && (Log() << Verbose(2) << "End of PickRandomPointSet" << endl);
365};
366
367/** Finds best fitting ellipsoid parameter set in least square sense for a given point set.
368 * \param *out output stream for debugging
369 * \param *T Tesselation containing boundary points
370 * \param *LCList linked cell list of all atoms
371 * \param N number of unique points in ellipsoid fit, must be greater equal 6
372 * \param number of fits (i.e. parameter sets in output file)
373 * \param *filename name for output file
374 */
375void FindDistributionOfEllipsoids(class Tesselation *T, class LinkedCell *LCList, int N, int number, const char *filename)
376{
377 ofstream output;
378 Vector *x = NULL;
379 Vector Center;
380 Vector EllipsoidCenter;
381 double EllipsoidLength[3];
382 double EllipsoidAngle[3];
383 double distance, MaxDistance, MinDistance;
384 DoLog(0) && (Log() << Verbose(0) << "Begin of FindDistributionOfEllipsoids" << endl);
385
386 // construct center of gravity of boundary point set for initial ellipsoid center
387 Center.Zero();
388 for (PointMap::iterator Runner = T->PointsOnBoundary.begin(); Runner != T->PointsOnBoundary.end(); Runner++)
389 Center.AddVector(Runner->second->node->node);
390 Center.Scale(1./T->PointsOnBoundaryCount);
391 DoLog(1) && (Log() << Verbose(1) << "Center is at " << Center << "." << endl);
392
393 // Output header
394 output.open(filename, ios::trunc);
395 output << "# Nr.\tCenterX\tCenterY\tCenterZ\ta\tb\tc\tpsi\ttheta\tphi" << endl;
396
397 // loop over desired number of parameter sets
398 for (;number >0;number--) {
399 DoLog(1) && (Log() << Verbose(1) << "Determining data set " << number << " ... " << endl);
400 // pick the point set
401 x = NULL;
402 //PickRandomPointSet(T, LCList, x, N);
403 PickRandomNeighbouredPointSet(T, LCList, x, N);
404
405 // calculate some sensible starting values for parameter fit
406 MaxDistance = 0.;
407 MinDistance = x[0].ScalarProduct(&x[0]);
408 for (int i=0;i<N;i++) {
409 distance = x[i].ScalarProduct(&x[i]);
410 if (distance > MaxDistance)
411 MaxDistance = distance;
412 if (distance < MinDistance)
413 MinDistance = distance;
414 }
415 //Log() << Verbose(2) << "MinDistance " << MinDistance << ", MaxDistance " << MaxDistance << "." << endl;
416 EllipsoidCenter.CopyVector(&Center); // use Center of Gravity as initial center of ellipsoid
417 for (int i=0;i<3;i++)
418 EllipsoidAngle[i] = 0.;
419 EllipsoidLength[0] = sqrt(MaxDistance);
420 EllipsoidLength[1] = sqrt((MaxDistance+MinDistance)/2.);
421 EllipsoidLength[2] = sqrt(MinDistance);
422
423 // fit the parameters
424 if (FitPointSetToEllipsoid(x, N, &EllipsoidCenter, &EllipsoidLength[0], &EllipsoidAngle[0])) {
425 DoLog(1) && (Log() << Verbose(1) << "Picking succeeded!" << endl);
426 // output obtained parameter set
427 output << number << "\t";
428 for (int i=0;i<3;i++)
429 output << setprecision(9) << EllipsoidCenter.x[i] << "\t";
430 for (int i=0;i<3;i++)
431 output << setprecision(9) << EllipsoidLength[i] << "\t";
432 for (int i=0;i<3;i++)
433 output << setprecision(9) << EllipsoidAngle[i] << "\t";
434 output << endl;
435 } else { // increase N to pick one more
436 DoLog(1) && (Log() << Verbose(1) << "Picking failed!" << endl);
437 number++;
438 }
439 delete[](x); // free allocated memory for point set
440 }
441 // close output and finish
442 output.close();
443
444 DoLog(0) && (Log() << Verbose(0) << "End of FindDistributionOfEllipsoids" << endl);
445};
Note: See TracBrowser for help on using the repository browser.