Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-03 08:19:42

0001 /**
0002  *
0003  * cornelius++ version 1.3: Copyright 2012, Pasi Huovinen and Hannu Holopainen
0004  *
0005  * This subroutine is aimed to be used as a part of the fluid dynamical models
0006  * of the heavy-ion physics community. Permission to use it for any purpose
0007  * except for any commercial purpose is granted, provided that any publication
0008  * cites the paper describing the algorithm:
0009  *   P. Huovinen and H. Petersen, arXiv:1206.3371 [nucl-th]
0010  *
0011  * Permission to distribute this subroutine is granted, provided that no fee is
0012  * charged, and that this copyright and permission notice appear in all the
0013  * copies. Permission to modify this subroutine is granted provided that the
0014  * modified subroutine is made publicly available latest when any results obtained
0015  * using the modified subroutine are published, the modified subroutine is
0016  * distributed under terms similar to this notice, and the modified code carries
0017  * both the original copyright notice and notices stating that you modified it,
0018  * and a relevant date/year.
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of FITNESS FOR A PARTICULAR PURPOSE. 
0022  *
0023  * Last update 03.08.2012 Hannu Holopainen
0024  *
0025  */
0026 
0027 #include <iostream>
0028 #include <fstream>
0029 #include <math.h>
0030 #include <stdlib.h>
0031 
0032 using namespace std;
0033 
0034 /**
0035  *
0036  * General class for elements. All other element classes are inherited
0037  * from this.
0038  *
0039  */
0040 class GeneralElement
0041 {
0042   protected:
0043     static const int DIM = 4;
0044     double *centroid;
0045     double *normal;
0046     int normal_calculated;
0047     int centroid_calculated;
0048     virtual void calculate_centroid() {};
0049     virtual void calculate_normal() {};
0050     void check_normal_direction(double *normal, double *out);
0051   public:
0052     GeneralElement();
0053     ~GeneralElement();
0054     double *get_centroid();
0055     double *get_normal();
0056 };
0057 
0058 /**
0059  *
0060  * Constructor allocates memory for centroid and normal. 
0061  *
0062  */
0063 GeneralElement::GeneralElement()
0064 {
0065   normal_calculated = 0;
0066   centroid_calculated = 0;
0067   centroid = new double[DIM];
0068   normal = new double[DIM];
0069 }
0070 
0071 /**
0072  *
0073  * Destructor frees memory.
0074  *
0075  */
0076 GeneralElement::~GeneralElement()
0077 {
0078   delete[] centroid;
0079   delete[] normal;
0080 }
0081 
0082 /**
0083  *
0084  * Checks if the normal is pointing into right direction. If the normal
0085  * is pointing in the wrong direction, it is turned to the right direction. 
0086  *
0087  * @param [in/out] normal The normal vector
0088  * @param [in]     out    Vector pointing into outward direction.
0089  *
0090  */
0091 void GeneralElement::check_normal_direction(double *normal, double *out)
0092 {
0093   //We calculate the dot product, if less than 4 dimensions the elements,
0094   //which are not used, are just zero and do not effect this
0095   double dot_product = 0;
0096   for (int i=0; i < DIM; i++) {
0097     dot_product += out[i]*normal[i];
0098   }
0099   //If the dot product is negative, the normal is pointing in the
0100   //wrong direction and we have to flip it's direction
0101   if ( dot_product < 0 ) {
0102     for (int i=0; i < DIM; i++) {
0103       normal[i] = -normal[i];
0104     }
0105   }
0106 }
0107 
0108 /**
0109  *
0110  * Returns the centroid as a (double*) always in 4d.
0111  *
0112  * @return Table containing centroid in 4D
0113  *
0114  */
0115 double *GeneralElement::get_centroid()
0116 {
0117   if ( !centroid_calculated )
0118     calculate_centroid();
0119   return centroid;
0120 }
0121 
0122 /**
0123  *
0124  * Returns the normal as a (double*) always in 4d.
0125  *
0126  * @return Table containing normal in 4D
0127  *
0128  */
0129 double *GeneralElement::get_normal()
0130 {
0131   if ( !normal_calculated )
0132     calculate_normal();
0133   return normal;
0134 }
0135 
0136 
0137 /**
0138  *
0139  * This class is used for line elements gotten from the squares. Can
0140  * calculate the centroid and normal of the line.
0141  *
0142  */
0143 class Line : public GeneralElement
0144 {
0145   private:
0146     static const int LINE_CORNERS = 2;
0147     static const int LINE_DIM = 2;
0148     int x1,x2;
0149     int start_point;
0150     int end_point;
0151     double **corners;
0152     double *out;
0153     int *const_i;
0154     void calculate_centroid();
0155     void calculate_normal();
0156   public:
0157     Line();
0158     ~Line();
0159     void init(double**,double*,int*);
0160     void flip_start_end();
0161     double *get_start();
0162     double *get_end();
0163     double *get_out();
0164 };
0165 
0166 /**
0167  *
0168  * Constructor allocates memory for end points, point which is always
0169  * outside and indices of the elements which are constant.
0170  *
0171  */
0172 Line::Line()
0173 {
0174   GeneralElement();
0175   corners = new double*[LINE_CORNERS];
0176   for (int i=0; i < LINE_CORNERS; i++) {
0177     corners[i] = new double[DIM];
0178   }
0179   out = new double[DIM];
0180   const_i = new int[DIM-LINE_DIM]; 
0181 }
0182 
0183 /**
0184  *
0185  * Frees memory allocated in constructor.
0186  *
0187  */
0188 Line::~Line()
0189 {
0190   for (int i=0; i < LINE_CORNERS; i++) {
0191     delete[] corners[i];
0192   }
0193   delete[] corners;
0194   delete[] out;
0195   delete[] const_i;
0196 }
0197 
0198 /**
0199  *
0200  * Initializes line element. Same element can be initialized several
0201  * times with this function.
0202  *
0203  * @param [in] p Table containing end points
0204  * @param [in] o Table containing point which is outside surface
0205  * @param [in] o Table containing constant indices
0206  *
0207  */
0208 void Line::init(double **p, double *o, int *c)
0209 {
0210   //We copy the values of the end points and the outside point
0211   for (int i=0; i < LINE_CORNERS; i++) {
0212     for (int j=0; j < DIM; j++) {
0213       corners[i][j] = p[i][j];
0214       if ( i==0 ) {
0215         out[j] = o[j];
0216       }
0217     }
0218   }
0219   //Let's set indices for start and end points, so we can conveniently
0220   //flip the start and end point without changing the actual values
0221   start_point = 0;
0222   end_point = 1;
0223   //Here we copy the indices which are constant at this line
0224   for (int i=0; i < DIM-LINE_DIM; i++) {
0225     const_i[i] = c[i];
0226   }
0227   //Here we fix the non-zero indices in such a way that x1 is
0228   //always smaller
0229   if ( c[0] == 0 ) {
0230     if ( c[1] == 1 ) {
0231       x1 = 2; x2 = 3;
0232     } else if ( c[1] == 2 ) {
0233       x1 = 1; x2 = 3;
0234     } else {
0235       x1 = 1; x2 = 2;
0236     }
0237   } else if ( c[0] == 1 ) {
0238     if ( c[1] == 2 ) {
0239       x1 = 0; x2 = 3;
0240     } else {
0241       x1 = 0; x2 = 2;
0242     }
0243   } else {
0244     x1 = 0; x2 = 1;
0245   }
0246   //We need to set these to zero so when this function is called
0247   //again we know that normal and centroid are not yet calculated
0248   //with new values
0249   normal_calculated = 0;
0250   centroid_calculated = 0;
0251 }
0252 
0253 /**
0254  *
0255  * Determines the centroid for a line. Thus this a very trivial
0256  * operation.
0257  *
0258  */
0259 void Line::calculate_centroid()
0260 {
0261   //Centroid is just the average of the points
0262   for (int i=0; i < DIM; i++) {
0263     centroid[i] = (corners[0][i] + corners[1][i])/2.0;
0264   }
0265   centroid_calculated = 1;
0266 }
0267 
0268 /**
0269  *
0270  * Calculates the normal vector for a line.
0271  *
0272  */
0273 void Line::calculate_normal()
0274 {
0275   //Centroid must be calculated before we can calculate normal
0276   if ( !centroid_calculated )
0277     calculate_centroid();
0278   //Normal is just (-dy,dx)
0279   normal[x1] = -(corners[1][x2] - corners[0][x2]);
0280   normal[x2] = corners[1][x1] - corners[0][x1];
0281   normal[const_i[0]] = 0;
0282   normal[const_i[1]] = 0;
0283   //Now we check if the normal is in the correct direction
0284   double *Vout = new double[DIM];
0285   for (int j=0; j < DIM; j++) {
0286     Vout[j] = out[j] - centroid[j];
0287   }
0288   check_normal_direction(normal,Vout);
0289   delete[] Vout;
0290   normal_calculated = 1;
0291 }
0292 
0293 /**
0294  *
0295  * Flips the start and end point of the line.
0296  *
0297  */
0298 void Line::flip_start_end()
0299 {
0300   int temp = start_point;
0301   start_point = end_point;
0302   end_point = temp;
0303 }
0304 
0305 /**
0306  *
0307  * Returns the start point in 4d as double*.
0308  *
0309  * @return Start point as a table
0310  *
0311  */
0312 double *Line::get_start()
0313 {
0314   return corners[start_point];
0315 }
0316 
0317 /**
0318  *
0319  * Returns the end point in 4d as double*.
0320  *
0321  * @return End point as a table
0322  *
0323  */
0324 double *Line::get_end()
0325 {
0326   return corners[end_point];
0327 }
0328 
0329 /**
0330  *
0331  * Returns the point, which is always outside, in 4d as double*.
0332  *
0333  * @return Point which is always outside as a table
0334  *
0335  */
0336 double *Line::get_out()
0337 {
0338   return out;
0339 }
0340 
0341 /**
0342  *
0343  * A class for storing polygons given by Cornelius. Can calculate
0344  * the centroid and normal of the polygon.
0345  *
0346  */
0347 class Polygon : public GeneralElement
0348 {
0349   private:
0350     static const int MAX_LINES = 24;
0351     static const int POLYGON_DIM = 3;
0352     Line **lines;
0353     int Nlines;
0354     int x1,x2,x3;
0355     int const_i;
0356     void calculate_centroid();
0357     void calculate_normal();
0358   public:
0359     Polygon();
0360     ~Polygon();
0361     void init(int);
0362     bool add_line(Line*,int);
0363     int get_Nlines();
0364     Line** get_lines();
0365     void print(ofstream &file,double*);
0366 };
0367 
0368 /**
0369  *
0370  * Allocates memory for the list of pointers to the lines which
0371  * form the polygon.
0372  *
0373  */
0374 Polygon::Polygon()
0375 {
0376   GeneralElement();
0377   lines = new Line*[MAX_LINES];
0378 }
0379 
0380 /**
0381  *
0382  * Frees memory allocated at the constructor.
0383  *
0384  */
0385 Polygon::~Polygon()
0386 {
0387   delete[] lines;
0388 }
0389 
0390 /**
0391  *
0392  * This initializes the polygon. Can be used several times.
0393  * 
0394  * @param [in] c Index which is constant in this polygon 
0395  *
0396  */
0397 void Polygon::init(int c)
0398 {
0399   //Let's copy the constant index
0400   const_i = c;
0401   //Here we fix the indices which are not constant
0402   x1 = -1;
0403   x2 = -1;
0404   x3 = -1;
0405   for (int i=0; i < DIM; i++) {
0406     if ( i != c ) {
0407       if ( x1 < 0 ) {
0408         x1 = i;
0409       } else if ( x2 < 0 ) {
0410         x2 = i;
0411       } else {
0412         x3 = i;
0413       }
0414     }
0415   }
0416   //We need to set these to zero so when this function is called
0417   //again we know that polygon has no lines added and normal and
0418   //centroid are not yet calculated with new values
0419   Nlines = 0;
0420   normal_calculated = 0;
0421   centroid_calculated = 0;
0422 }
0423 
0424 /**
0425  *
0426  * Adds a line to the polygon. This can also check if the line
0427  * is connected to the ones already in the polygon and the line
0428  * is added only when the line is connected. 
0429  * 
0430  * @param [in] l          Line which is tried to add to polygon 
0431  * @param [in] donotcheck 1 if no check is needed, 0 otherwise
0432  *
0433  * @return True if line was added, false if not added
0434  *
0435  */
0436 bool Polygon::add_line(Line *l, int donotcheck)
0437 {
0438   double eps = 1e-10;
0439   //If this is the first line or we do not want to check, line is added
0440   //automatically
0441   if ( donotcheck || Nlines == 0 ) {
0442     lines[Nlines] = l;
0443     Nlines++;
0444     return true; 
0445   } else {
0446     //Here we check if the new line is connected with the last line in
0447     //polygon. This since lines are ordered.
0448     double *p1 =  l->get_start();
0449     double *p2 =  l->get_end();
0450     double *p3 =  lines[Nlines-1]->get_end();
0451     double diff1 = 0;
0452     double diff2 = 0;
0453     for (int j=0; j < DIM; j++) {
0454       diff1 += fabs(p1[j]-p3[j]);
0455       diff2 += fabs(p2[j]-p3[j]);
0456     }
0457     //If start or end point is the same as the end point of previous line, line
0458     //is connected to polygon and it is added
0459     if ( diff1 < eps || diff2 < eps ) {
0460       //We always want that start point is connected to end so we flip the
0461       //start and end in the new line if needed
0462       if ( diff2 < eps )
0463         l->flip_start_end();
0464       lines[Nlines] = l;
0465       Nlines++;
0466       return true;
0467     }
0468     //If we are here, the line was not connected to the current polygon
0469     return false;
0470   }
0471 }
0472 
0473 /**
0474  *
0475  * This determines the centroid (center of mass) of the polygon.
0476  *
0477  */
0478 void Polygon::calculate_centroid()
0479 {
0480   //We need a vector for the mean of the corners.
0481   double *mean = new double[DIM];
0482   for (int i=0; i < DIM; i++ ) {
0483     mean[i] = 0;
0484   }
0485   //First we determine the mean of the corner points. Every point
0486   //is here twice since lines are not ordered
0487   for (int i=0; i < Nlines; i++ ) {
0488     double *p1 = lines[i]->get_start(); 
0489     double *p2 = lines[i]->get_end(); 
0490     for (int j=0; j < DIM; j++ ) {
0491       mean[j] += p1[j] + p2[j];
0492     }
0493   }
0494   for (int j=0; j < DIM; j++ ) {
0495     mean[j] = mean[j]/double(2.0*Nlines);
0496   }
0497   //If only 3 lines, i.e. 3 corners, the polygon is always on a plane
0498   //and centroid is the mean
0499   if ( Nlines == 3 ) {
0500     for (int i=0; i < DIM; i++) {
0501       centroid[i] = mean[i];
0502     }
0503     centroid_calculated = 1;
0504     delete[] mean;
0505     return;
0506   }
0507   //If more than 3 corners, calculation of the centroid is more
0508   //complicated
0509   //Here we from triangles from the lines and the mean point
0510   double *sum_up = new double[DIM]; //areas of the single triangles 
0511   double sum_down = 0; //area of all the triangles
0512   for (int i=0; i < DIM; i++) {
0513     sum_up[i] = 0;
0514   }
0515   //a and b are vectors which from the triangle
0516   double *a = new double[DIM];
0517   double *b = new double[DIM];
0518   //centroid of the triangle (this is always on a plane)
0519   double *cm_i = new double[DIM];
0520   for (int i=0; i < Nlines; i++) {
0521     double *p1 = lines[i]->get_start();
0522     double *p2 = lines[i]->get_end();
0523     for (int j=0; j < DIM; j++) {
0524       cm_i[j] = (p1[j] + p2[j] + mean[j])/3.0;
0525     } 
0526     //Triangle is defined by these two vectors
0527     for (int j=0; j < DIM; j++) {
0528       a[j] = p1[j] - mean[j];
0529       b[j] = p2[j] - mean[j];
0530     }
0531     //Area is calculated from cross product of these vectors
0532     double A_i = 0.5*sqrt( pow(a[x2]*b[x3]-a[x3]*b[x2],2.0) + pow(a[x1]*b[x3]-a[x3]*b[x1],2.0) + pow(a[x2]*b[x1]-a[x1]*b[x2],2.0) );
0533     //Then we store the area and update the total area
0534     for (int j=0; j < DIM; j++) {
0535       sum_up[j] += cm_i[j]*A_i;
0536     }
0537     sum_down += A_i;
0538   }
0539   //Now we can determine centroid as a weighted average of the centroids
0540   //of the triangles
0541   for (int i=0; i < DIM; i++) {
0542     centroid[i] = sum_up[i]/sum_down;
0543   }
0544   //centroid is now calculated and memory is freed
0545   centroid_calculated = 1;
0546   delete[] sum_up;
0547   delete[] mean;
0548   delete[] a;
0549   delete[] b;
0550   delete[] cm_i;
0551 }
0552 
0553 /**
0554  *
0555  * Determines the normal vector for polygon. Makes sure that
0556  * it points in the outward direction.
0557  *
0558  */
0559 void Polygon::calculate_normal()
0560 {
0561   //centroid must be calculated before normal can be determined
0562   if ( !centroid_calculated )
0563     calculate_centroid();
0564   //First we find the normal for each triangle formed from
0565   //one edge and centroid
0566   double **normals = new double*[Nlines]; //these are the normals
0567   double *Vout = new double[DIM]; //the point which is always outside
0568   for (int i=0; i < Nlines; i++) {
0569     normals[i] = new double[DIM];
0570     for (int j=0; j < DIM; j++) {
0571       normals[i][j] = 0;
0572     }
0573   }
0574   //Normal is defined by these two vectors
0575   double *a = new double[DIM];
0576   double *b = new double[DIM];
0577   //Loop over all triangles
0578   for (int i=0; i < Nlines; i++) {
0579     //First we calculate the vectors which form the triangle
0580     double *p1 = lines[i]->get_start();
0581     double *p2 = lines[i]->get_end();
0582     for (int j=0; j < DIM; j++) {
0583       a[j] = p1[j] - centroid[j];
0584       b[j] = p2[j] - centroid[j];
0585     }
0586     //Normal is calculated as a cross product of these vectors
0587     normals[i][x1] =  0.5*(a[x2]*b[x3]-a[x3]*b[x2]);
0588     normals[i][x2] = -0.5*(a[x1]*b[x3]-a[x3]*b[x1]);
0589     normals[i][x3] =  0.5*(a[x1]*b[x2]-a[x2]*b[x1]);
0590     normals[i][const_i] = 0;
0591     //Then we construct a vector which points out
0592     double *o = lines[i]->get_out();
0593     for (int j=0; j < DIM; j++) {
0594       Vout[j] = o[j] - centroid[j];
0595     }
0596     //then we check that normal is point in the correct direction
0597     check_normal_direction(normals[i],Vout);
0598   }
0599   //Finally the normal is a sum of the normals of the triangles
0600   for (int i=0; i < DIM; i++) {
0601     normal[i] = 0;
0602   }
0603   for (int i=0; i < Nlines; i++) {
0604     for (int j=0; j < DIM; j++) {
0605       normal[j] += normals[i][j];
0606     }
0607   }
0608   //Normal is now calculated and memory can be freed
0609   normal_calculated = 1;
0610   delete[] a;
0611   delete[] b;
0612   for (int i=0; i < Nlines; i++) {
0613     delete[] normals[i];
0614   }
0615   delete[] normals;
0616   delete[] Vout;
0617 }
0618 
0619 /**
0620  *
0621  * Return the number of lines in this polygon.
0622  *
0623  * @return Number of lines in this polygon
0624  *
0625  */
0626 int Polygon::get_Nlines()
0627 {
0628   return Nlines;
0629 }
0630 
0631 /**
0632  *
0633  * Returns an array of pointers of the lines in the polygon.
0634  *
0635  * @return Array of pointer to the lines in polygon
0636  *
0637  */
0638 Line** Polygon::get_lines()
0639 {
0640   return lines;
0641 }
0642 
0643 /**
0644  *
0645  * Prints the triangles formed from the polygon into a given file. Prints
0646  * the absolute points, so this file can be used to plot the surface.
0647  *
0648  * @param [in] file Output stream where the points are printed.
0649  * @param [in] file Absolute position of the cube point (0,0,0) 
0650  *
0651  */
0652 void Polygon::print(ofstream &file, double *pos)
0653 {
0654   for (int i=0; i < Nlines; i++) {
0655     double *p1 = lines[i]->get_start();
0656     double *p2 = lines[i]->get_end();
0657     file << pos[x1] + p1[x1] << " " << pos[x2] + p1[x2]  << " " << pos[x3] + p1[x3];
0658     file << " " << pos[x1] + p2[x1] << " " << pos[x2] + p2[x2]  << " " << pos[x3] + p2[x3];
0659     file << " " << pos[x1] + centroid[x1] << " " << pos[x2] + centroid[x2]  << " " << pos[x3] + centroid[x3] << endl;
0660   }
0661 }
0662 
0663 /**
0664  *
0665  * A class for storing polyhedrons given by Cornelius. Can calculate
0666  * the normal and centroid of the polyhedron.
0667  *
0668  */
0669 class Polyhedron : public GeneralElement
0670 {
0671   private:
0672     static const int MAX_POLYGONS = 24;
0673     Polygon **polygons;
0674     int Npolygons;
0675     int Ntetrahedra;
0676     int x1,x2,x3,x4;
0677     bool lines_equal(Line*,Line*);
0678     void tetravolume(double*,double*,double*,double*);
0679     void calculate_centroid();
0680     void calculate_normal();
0681   public:
0682     Polyhedron();
0683     ~Polyhedron();
0684     void init();
0685     bool add_polygon(Polygon*,int);
0686 };
0687 
0688 /**
0689  * 
0690  * Allocates memory for a list pointers to the polygons which form
0691  * the polyhedron.
0692  *
0693  */
0694 Polyhedron::Polyhedron()
0695 {
0696   GeneralElement();
0697   polygons = new Polygon*[MAX_POLYGONS];
0698 }
0699 
0700 /**
0701  *
0702  * Frees memory allocated at the constructor.
0703  *
0704  */
0705 Polyhedron::~Polyhedron()
0706 {
0707   delete[] polygons;
0708 }
0709 
0710 /**
0711  *
0712  * This initializes the polygon. Can be used several times.
0713  * 
0714  */
0715 void Polyhedron::init()
0716 {
0717   //Here we fix the non-constant indices
0718   x1 = 0;
0719   x2 = 1;
0720   x3 = 2;
0721   x4 = 3;
0722   //We need to set these to zero so when this function is called
0723   //again we know that polyhedron has no polyfons added and normal
0724   //and centroid are not yet calculated with new values
0725   Npolygons = 0;
0726   Ntetrahedra = 0;
0727   normal_calculated = 0;
0728   centroid_calculated = 0;
0729 }
0730 
0731 /**
0732  *
0733  * Adds a polygon to the polyhedron. Also possible to check if the new
0734  * polygon is connected with previous polygons and only make the addition
0735  * if this is the case.
0736  * 
0737  * @param [in] p          Polygon which is tried to add to polyhedron
0738  * @param [in] donotcheck 1 if no check is needed, 0 otherwise
0739  *
0740  * @return True if polygon was added, false if not added
0741  *
0742  */
0743 bool Polyhedron::add_polygon(Polygon *p, int donocheck)
0744 {
0745   //If this is the first polygon or we want to add it in any case, we
0746   //just add it automatically
0747   if ( donocheck || Npolygons == 0 ) {
0748     polygons[Npolygons] = p;
0749     Npolygons++;
0750     Ntetrahedra += p->get_Nlines();
0751     return true; 
0752   } else {
0753     //Here we check if the new polygon is connected with the last polygon in
0754     //polyhedron
0755     for (int i=0; i < Npolygons; i++) {
0756       int Nlines1 = p->get_Nlines();
0757       int Nlines2 = polygons[i]->get_Nlines();
0758       Line **lines1 = p->get_lines();
0759       Line **lines2 = polygons[i]->get_lines();
0760       for (int j=0; j < Nlines1; j++) {
0761         for (int k=0; k < Nlines2; k++) {
0762           if ( lines_equal(lines1[j],lines2[k]) ) {
0763             polygons[Npolygons] = p;
0764             Npolygons++;
0765             Ntetrahedra += p->get_Nlines();
0766             return true; 
0767           }
0768         }
0769       }
0770     }
0771     //If we are here, the polygon was not connected to polyhedron
0772     return false;
0773   }
0774 }
0775 
0776 /**
0777  *
0778  * Checks if two lines are connected.
0779  * 
0780  * @param [in] l1 Line 1
0781  * @param [in] l2 Line 2
0782  *
0783  * @return true if lines are connected, false if not 
0784  *
0785  */
0786 bool Polyhedron::lines_equal(Line *l1, Line *l2)
0787 {
0788   double eps = 1e-10;
0789   double *p11 = l1->get_start();
0790   double *p12 = l1->get_end();
0791   double *p21 = l2->get_start();
0792   double diff1 = 0;
0793   double diff2 = 0;
0794   for (int i=0; i < DIM; i++) {
0795     diff1 += fabs(p11[i]-p21[i]);
0796     diff2 += fabs(p12[i]-p21[i]);
0797     if ( diff1 > eps && diff2 > eps )
0798       return false;
0799   }
0800   //If we are here, the lines are connected
0801   return true;
0802 }
0803 
0804 /**
0805  *
0806  * Calculates the normal vector for tetrahedra, which also tells
0807  * the volume of the tetrahedra.
0808  *
0809  * @param [in]  a Vector that spans the tetrahedra
0810  * @param [in]  b Vector that spans the tetrahedra
0811  * @param [in]  c Vector that spans the tetrahedra
0812  * @param [out] n Normal vector for tetrahedra
0813  *
0814  */
0815 void Polyhedron::tetravolume(double *a, double *b, double *c, double *n)
0816 {
0817   double bc01 = b[0]*c[1]-b[1]*c[0];
0818   double bc02 = b[0]*c[2]-b[2]*c[0];
0819   double bc03 = b[0]*c[3]-b[3]*c[0];
0820   double bc12 = b[1]*c[2]-b[2]*c[1];
0821   double bc13 = b[1]*c[3]-b[3]*c[1];
0822   double bc23 = b[2]*c[3]-b[3]*c[2];
0823   n[0] =  1.0/6.0*(a[1]*bc23 - a[2]*bc13 + a[3]*bc12);
0824   n[1] = -1.0/6.0*(a[0]*bc23 - a[2]*bc03 + a[3]*bc02);
0825   n[2] =  1.0/6.0*(a[0]*bc13 - a[1]*bc03 + a[3]*bc01);
0826   n[3] = -1.0/6.0*(a[0]*bc12 - a[1]*bc02 + a[2]*bc01);
0827   /*n[0] =  1.0/6.0*(a[1]*(b[2]*c[3]-b[3]*c[2]) - a[2]*(b[1]*c[3]-b[3]*c[1])
0828                   +a[3]*(b[1]*c[2]-b[2]*c[1]));
0829   n[1] = -1.0/6.0*(a[0]*(b[2]*c[3]-b[3]*c[2]) - a[2]*(b[0]*c[3]-b[3]*c[0])
0830                   +a[3]*(b[0]*c[2]-b[2]*c[0]));
0831   n[2] =  1.0/6.0*(a[0]*(b[1]*c[3]-b[3]*c[1]) - a[1]*(b[0]*c[3]-b[3]*c[0])
0832                   +a[3]*(b[0]*c[1]-b[1]*c[0]));
0833   n[3] = -1.0/6.0*(a[0]*(b[1]*c[2]-b[2]*c[1]) - a[1]*(b[0]*c[2]-b[2]*c[0])
0834                   +a[2]*(b[0]*c[1]-b[1]*c[0]));*/
0835 }
0836 
0837 /**
0838  *
0839  * This determines the centroid (center of mass) of the polyhedron.
0840  * 
0841  */
0842 void Polyhedron::calculate_centroid()
0843 {
0844   double *mean = new double[DIM];
0845   for (int i=0; i < DIM; i++ ) {
0846     mean[i] = 0;
0847   }
0848   //First we determine the mean of the corners
0849   for (int i=0; i < Npolygons; i++ ) {
0850     int Nlines = polygons[i]->get_Nlines();
0851     Line **lines = polygons[i]->get_lines();
0852     for (int j=0; j < Nlines; j++ ) {
0853       double *p1 = lines[j]->get_start();
0854       double *p2 = lines[j]->get_end();
0855       for (int k=0; k < DIM; k++ ) {
0856         mean[k] += p1[k] + p2[k];
0857       }
0858     }
0859   }
0860   for (int j=0; j < DIM; j++ ) {
0861     mean[j] = mean[j]/double(2.0*Ntetrahedra);
0862   }
0863   //Some memory allocated for temporary variables
0864   double *a = new double[DIM];
0865   double *b = new double[DIM];
0866   double *c = new double[DIM];
0867   double *n = new double[DIM];
0868   double *cm_i = new double[DIM];
0869   double *sum_up = new double[DIM];
0870   double sum_down = 0;
0871   for (int i=0; i < DIM; i++) {
0872     sum_up[i] = 0;
0873   }
0874   for (int i=0; i < Npolygons; i++ ) {
0875     int Nlines = polygons[i]->get_Nlines();
0876     Line **lines = polygons[i]->get_lines();
0877     double *cent = polygons[i]->get_centroid();
0878     for (int j=0; j < Nlines; j++) {
0879       double *p1 = lines[j]->get_start();
0880       double *p2 = lines[j]->get_end();
0881       //CM of the tetrahedra
0882       for (int k=0; k < DIM; k++) {
0883         cm_i[k] = (p1[k] + p2[k] + cent[k] + mean[k])/4.0;
0884       } 
0885       //Volume of a tetrahedron is determined next
0886       //Tetrahedron is defined by these three vectors
0887       for (int k=0; k < DIM; k++) {
0888         a[k] = p1[k] - mean[k];
0889         b[k] = p2[k] - mean[k];
0890         c[k] = cent[k] - mean[k];
0891       }
0892       //Then we calculate the volume from the normal n 
0893       tetravolume(a,b,c,n);
0894       double V_i = 0; 
0895       for (int k=0; k < DIM; k++) {
0896         V_i += n[k]*n[k];
0897       }
0898       V_i = sqrt(V_i);
0899       //Then we add contributions to sums
0900       for (int k=0; k < DIM; k++) {
0901         sum_up[k] += cm_i[k]*V_i;
0902       }
0903       sum_down += V_i;
0904     }
0905   }
0906   //Now the centroid is the volume weighted average of individual
0907   //tetrahedra
0908   for (int i=0; i < DIM; i++) {
0909     centroid[i] = sum_up[i]/sum_down;
0910   }
0911   //Centroid is now calculated and we can free memory
0912   centroid_calculated = 1;
0913   delete[] a;
0914   delete[] b;
0915   delete[] c;
0916   delete[] n;
0917   delete[] cm_i;
0918   delete[] sum_up;
0919   delete[] mean;
0920 }
0921 
0922 /**
0923  *
0924  * Determines the normal vector for polygon. Makes sure that
0925  * it points in the outward direction.
0926  *
0927  */
0928 void Polyhedron::calculate_normal()
0929 {
0930   //We need centroid in the following calculation and thus we
0931   //need to check that it is calculated
0932   if ( !centroid_calculated )
0933     calculate_centroid();
0934   //First we allocate memory for temporary variables
0935   double *Vout = new double[DIM];
0936   double *a = new double[DIM];
0937   double *b = new double[DIM];
0938   double *c = new double[DIM];
0939   double **normals = new double*[Ntetrahedra];
0940   for (int i=0; i < Ntetrahedra; i++) {
0941     normals[i] = new double[DIM];
0942   }
0943   int Ntetra = 0; //Index of tetrahedron we are dealing with
0944   for (int i=0; i < Npolygons; i++ ) {
0945     int Nlines = polygons[i]->get_Nlines();
0946     Line **lines = polygons[i]->get_lines();
0947     double *cent = polygons[i]->get_centroid();
0948     for (int j=0; j < Nlines; j++) {
0949       double *p1 = lines[j]->get_start();
0950       double *p2 = lines[j]->get_end();
0951       //Tetrahedron is defined by these three vectors
0952       for (int k=0; k < DIM; k++) {
0953         a[k] = p1[k] - centroid[k];
0954         b[k] = p2[k] - centroid[k];
0955         c[k] = cent[k] - centroid[k];
0956       }
0957       //Normal is calculated with the same function as volume
0958       tetravolume(a,b,c,normals[Ntetra]);
0959       //Then we determine the direction towards lower energy
0960       double *o = lines[j]->get_out();
0961       for (int k=0; k < DIM; k++) {
0962         Vout[k] = o[k] - centroid[k];
0963       }
0964       check_normal_direction(normals[Ntetra],Vout);
0965       Ntetra++;
0966     }
0967   }
0968   //Finally the element normal is a sum of the calculated normals
0969   for (int i=0; i < DIM; i++) {
0970     normal[i] = 0;
0971   }
0972   for (int i=0; i < Ntetrahedra; i++) {
0973     for (int j=0; j < DIM; j++) {
0974       normal[j] += normals[i][j];
0975     }
0976   }
0977   //Normal is now determined and we can free memory
0978   normal_calculated = 1;
0979   for (int i=0; i < Ntetrahedra; i++) {
0980     delete[] normals[i];
0981   }
0982   delete[] a;
0983   delete[] b;
0984   delete[] c;
0985   delete[] normals;
0986   delete[] Vout;
0987 }
0988 
0989 /**
0990  *
0991  * This class handles the squares. Finds the edges of the surface and also
0992  * the points which are always outside the surface so that we can determine
0993  * correct direction for normal vector.
0994  *
0995  */
0996 class Square
0997 {
0998   private:
0999     static const int DIM = 4;
1000     static const int SQUARE_DIM = 2;
1001     static const int MAX_POINTS = 4;
1002     static const int MAX_LINES = 2;
1003     double **points;
1004     double **cuts;
1005     double **out;
1006     double **points_temp;
1007     double *out_temp;
1008     int *const_i;
1009     double *const_value;
1010     int x1, x2;
1011     double *dx;
1012     int Ncuts;
1013     int Nlines;
1014     Line *lines;
1015     int ambiguous;
1016     void ends_of_edge(double);
1017     void find_outside(double);
1018   public:
1019     Square();
1020     ~Square();
1021     void init(double**,int*,double*,double*);
1022     void construct_lines(double);
1023     int is_ambiguous();
1024     int get_Nlines();
1025     Line* get_lines();
1026 };
1027 
1028 /**
1029  *
1030  * Constructor allocates memory for the basic things needed in the
1031  * process.
1032  *
1033  */
1034 Square::Square()
1035 {
1036   cuts = new double*[MAX_POINTS];
1037   out = new double*[MAX_POINTS];
1038   points = new double*[SQUARE_DIM];
1039   const_i = new int[DIM-SQUARE_DIM];
1040   const_value = new double[DIM-SQUARE_DIM];
1041   lines = new Line[MAX_LINES];
1042   for (int i=0; i < SQUARE_DIM; i++) {
1043     points[i] = new double[SQUARE_DIM];
1044   }
1045   for (int i=0; i < MAX_POINTS; i++) {
1046     cuts[i] = new double[SQUARE_DIM];
1047     out[i] = new double[SQUARE_DIM];
1048   }
1049   int Npoints = 2;
1050   points_temp = new double*[SQUARE_DIM];
1051   out_temp = new double[DIM];
1052   for (int j=0; j < Npoints; j++) {
1053     points_temp[j] = new double[DIM];
1054   }
1055   ambiguous = 0;
1056 }
1057 
1058 /**
1059  *
1060  * Destructor frees memory allocated in the constructor.
1061  *
1062  */
1063 Square::~Square()
1064 {
1065   for (int i=0; i < DIM-SQUARE_DIM; i++) {
1066     delete[] points[i];
1067   }
1068   delete[] points;
1069   for (int i=0; i < MAX_POINTS; i++) {
1070     delete[] cuts[i];
1071     delete[] out[i];
1072   }
1073   delete[] cuts;
1074   delete[] out;
1075   delete[] const_i;
1076   delete[] const_value;
1077   delete[] lines;
1078   for (int i=0; i < SQUARE_DIM; i++) {
1079     delete[] points_temp[i];
1080   }
1081   delete[] points_temp;
1082   delete[] out_temp;
1083 }
1084 
1085 /**
1086  *
1087  * Initializes the square. Can be used several times to replace the old square
1088  * with a new one.
1089  *
1090  * @param [in] sq    Values at ends of the square.
1091  * @param [in] c_i   Indices that are constant on this square
1092  * @param [in] s_i   Indices that are x and y in this square
1093  * @param [in] c_val Values for the constant indices
1094  * @param [in] dex   Length of sides x and y
1095  *
1096  */
1097 void Square::init(double **sq, int *c_i, double *c_v, double *dex)
1098 {
1099   for (int i=0; i < SQUARE_DIM; i++) {
1100     for (int j=0; j < SQUARE_DIM; j++) {
1101       points[i][j] = sq[i][j];
1102     }
1103   }
1104   for (int i=0; i < DIM-SQUARE_DIM; i++) {
1105     const_i[i] = c_i[i];
1106     const_value[i] = c_v[i];
1107   }
1108   dx = dex;
1109   x1 = -1;
1110   x2 = -1;
1111   for (int i=0; i < DIM; i++) {
1112     if ( i != const_i[0] && i != const_i[1] ) {
1113       if ( x1 < 0 ) {
1114         x1 = i;
1115       } else {
1116         x2 = i;
1117       }
1118     }
1119   }
1120   //We need to set these to zero so when this function is called
1121   //again we know that nothing has been done for this square
1122   Ncuts = 0;
1123   Nlines = 0;
1124   ambiguous = 0;
1125 }
1126 
1127 /**
1128  *
1129  * Construct the lines which represent the surface on this square.
1130  *
1131  * @param [in] E0 The value which defines surface
1132  *
1133  */
1134 void Square::construct_lines(double E0)
1135 {
1136   //First we check the corner points and see if there are any lines
1137   int above=0;
1138   for (int i=0; i < DIM-SQUARE_DIM; i++) {
1139     for (int j=0; j < DIM-SQUARE_DIM; j++) {
1140       if ( points[i][j] >= E0 )
1141         above++; 
1142     }
1143   }
1144   //If all corners are above or below the surface value, no lines in this
1145   //square
1146   if ( above == 0 || above == 4 ) {
1147     Nlines = 0;
1148     return;
1149   }
1150   //First we find the cut points and the points which are always outside of the
1151   //surface. Also find_outside() arranges cuts so that first two cuts form a line
1152   //as defined in the algorithm (in case there are 4 cuts)
1153   ends_of_edge(E0);
1154   if ( Ncuts > 0 )
1155     find_outside(E0);
1156   //Then we go through the cut points and form the line elements 
1157   for (int i=0; i < Ncuts; i++) {
1158     points_temp[i%2][x1] = cuts[i][0];
1159     points_temp[i%2][x2] = cuts[i][1];
1160     points_temp[i%2][const_i[0]] = const_value[0];
1161     points_temp[i%2][const_i[1]] = const_value[1];
1162     //When we have inserted both endpoints we insert outside point
1163     //and we are ready to create line element.
1164     if ( i%2 == 1 ) {
1165       out_temp[x1] = out[i/2][0];
1166       out_temp[x2] = out[i/2][1];
1167       out_temp[const_i[0]] = const_value[0];
1168       out_temp[const_i[1]] = const_value[1];
1169       lines[i/2].init(points_temp,out_temp,const_i);
1170       Nlines++;
1171     }
1172   }
1173 }
1174 
1175 /**
1176  *
1177  * This finds the points from the edges where the surface crosses
1178  * the given square.
1179  *
1180  * The edges are gone through in the following order
1181  *      4
1182  *    -----
1183  *  1 |   | 3
1184  *    -----
1185  *      2
1186  * Since in the case where the ends are on each edge the ends are
1187  * assumed to be connected like \\
1188  *
1189  * @param [in] E0 Value that defines this surface
1190  *
1191  */
1192 void Square::ends_of_edge(double E0)
1193 {
1194   //Edge 1
1195   if ( (points[0][0]-E0)*(points[1][0]-E0) < 0 ) {
1196     cuts[Ncuts][0] = (points[0][0]-E0)/(points[0][0]-points[1][0])*dx[x1];
1197     cuts[Ncuts][1] = 0;
1198     Ncuts++;
1199   } else if ( points[0][0] == E0 && points[1][0] < E0 ) {
1200     cuts[Ncuts][0] = 1e-9*dx[x1];
1201     cuts[Ncuts][1] = 0;
1202     Ncuts++;
1203   } else if ( points[1][0] == E0 && points[0][0] < E0 ) {
1204     cuts[Ncuts][0] = (1.0-1e-9)*dx[x1];
1205     cuts[Ncuts][1] = 0;
1206     Ncuts++;
1207   }
1208   //Edge 2
1209   if ( (points[0][0]-E0)*(points[0][1]-E0) < 0 ) {
1210     cuts[Ncuts][0] = 0;
1211     cuts[Ncuts][1] = (points[0][0]-E0)/(points[0][0]-points[0][1])*dx[x2];
1212     Ncuts++;
1213   } else if ( points[0][0] == E0 && points[0][1] < E0 ) {
1214     cuts[Ncuts][0] = 0;
1215     cuts[Ncuts][1] = 1e-9*dx[x2];
1216     Ncuts++;
1217   } else if ( points[0][1] == E0 && points[0][0] < E0 ) {
1218     cuts[Ncuts][0] = 0;
1219     cuts[Ncuts][1] = (1.0-1e-9)*dx[x2];
1220     Ncuts++;
1221   }
1222   //Edge 3
1223   if ( (points[1][0]-E0)*(points[1][1]-E0) < 0 ) {
1224     cuts[Ncuts][0] = dx[x1];
1225     cuts[Ncuts][1] = (points[1][0]-E0)/(points[1][0]-points[1][1])*dx[x2];
1226     Ncuts++;
1227   } else if ( points[1][0] == E0 && points[1][1] < E0 ) {
1228     cuts[Ncuts][0] = dx[x1];
1229     cuts[Ncuts][1] = 1e-9*dx[x2];
1230     Ncuts++;
1231   } else if ( points[1][1] == E0 && points[1][0] < E0 ) {
1232     cuts[Ncuts][0] = dx[x1];
1233     cuts[Ncuts][1] = (1.0-1e-9)*dx[x2];
1234     Ncuts++;
1235   }
1236   //Edge 4
1237   if ( (points[0][1]-E0)*(points[1][1]-E0) < 0 ) {
1238     cuts[Ncuts][0] = (points[0][1]-E0)/(points[0][1]-points[1][1])*dx[x1];
1239     cuts[Ncuts][1] = dx[x2];
1240     Ncuts++;
1241   } else if ( points[0][1] == E0 && points[1][1] < E0 ) {
1242     cuts[Ncuts][0] = 1e-9*dx[x1];
1243     cuts[Ncuts][1] = dx[x2];
1244     Ncuts++;
1245   } else if ( points[1][1] == E0 && points[0][1] < E0 ) {
1246     cuts[Ncuts][0] = (1.0-1e-9)*dx[x1];
1247     cuts[Ncuts][1] = dx[x2];
1248     Ncuts++;
1249   }
1250   if ( Ncuts != 0 && Ncuts != 2 && Ncuts != 4 ) {
1251     cout << "Error in EndsOfEdge: Ncuts " << Ncuts << endl;
1252     exit(1);
1253   }
1254 }
1255 
1256 /**
1257  *
1258  * Finds the points showing the outside direction. 
1259  *
1260  * @param [in] E0 Value that defines this surface
1261  *
1262  */
1263 void Square::find_outside(double E0)
1264 {
1265   if ( Ncuts == 4 ) { //Here the surface is ambiguous
1266     ambiguous = 1;
1267     //Let's calculate the value in the middle of the square
1268     double Emid = 0;
1269     for (int i=0; i < 2; i++) {
1270       for (int j=0; j < 2; j++) {
1271         Emid += 0.25*points[i][j];
1272       }
1273     }
1274     //The default is that cuts are connected as \\ here
1275     //If both Emid and (0,0) are above or below the criterion
1276     //the cuts should be like // and we have to switch order in cuts
1277     if ( (points[0][0] < E0 && Emid < E0) || (points[0][0] > E0 && Emid > E0) ) {
1278       for (int i=0; i < 2; i++) {
1279         double temp = cuts[1][i];
1280         cuts[1][i] = cuts[2][i];
1281         cuts[2][i] = temp;
1282       }
1283     }
1284     //The center is below, so the middle point is always outside
1285     //the surface
1286     if ( (Emid-E0) < 0 ) {
1287       for (int i=0; i < 2; i++) {
1288         for (int j=0; j < 2; j++) {
1289           if ( j == 0 )
1290             out[i][j] = 0.5*dx[x1];
1291           else
1292             out[i][j] = 0.5*dx[x2];
1293         }
1294       }
1295     } else { // The center is above
1296        // Cuts are \\ here so bl and tr corners are outside
1297       if ( (points[0][0]-E0) < 0 ) {
1298         for (int i=0; i < 2; i++) {
1299           out[0][i] = 0;
1300           if ( i == 0 )
1301             out[1][i] = dx[x1];
1302           else
1303             out[1][i] = dx[x2];
1304         }
1305       // Cuts are // here so br and tl corners are outside
1306       } else {
1307         out[0][0] = dx[x1];
1308         out[0][1] = 0;
1309         out[1][0] = 0;
1310         out[1][1] = dx[x2];
1311       }
1312     }
1313   } else { //This is the normal case (not ambiguous)
1314     for (int i=0; i < 2; i++) {
1315       for (int j=0; j < 2; j++) {
1316         out[i][j] = 0;
1317       }
1318     }
1319     int Nout = 0;
1320     for (int i=0; i < 2; i++) {
1321       for (int j=0; j < 2; j++) {
1322         if ( points[i][j] < E0 ) {
1323           out[0][0] += i*dx[x1];
1324           out[0][1] += j*dx[x2];
1325           Nout++;
1326         }
1327       }
1328     }
1329     if ( Nout > 0 ) {
1330       for (int i=0; i < 2; i++) {
1331         for (int j=0; j < 2; j++) {
1332           out[i][j] = out[i][j]/double(Nout);
1333         }
1334       }
1335     }
1336   }
1337 }
1338 
1339 /**
1340  *
1341  * Tells if the case is ambiguous in this square.
1342  *
1343  * @return Zero if not ambiguous, one if ambiguous
1344  *
1345  */
1346 int Square::is_ambiguous()
1347 {
1348   return ambiguous;
1349 }
1350 
1351 /**
1352  *
1353  * Returns the number of lines in this square.
1354  * 
1355  * @return Number of lines in this square
1356  *
1357  */
1358 int Square::get_Nlines()
1359 {
1360   return Nlines;
1361 }
1362 
1363 /**
1364  *
1365  * Returns a table containing the lines found from this square.
1366  *
1367  * @return List of lines found from square
1368  *
1369  */
1370 Line* Square::get_lines()
1371 {
1372   return lines;
1373 }
1374 
1375 
1376 /**
1377  *
1378  * This class handles 3d-cubes. Splits them into squares and collects
1379  * polygons from the lines given from squares.
1380  *
1381  */
1382 class Cube
1383 {
1384   private:
1385     static const int DIM = 4;
1386     static const int CUBE_DIM = 4;
1387     static const int MAX_POLY = 8;
1388     static const int NSQUARES = 6;
1389     static const int STEPS = 2;
1390     double ***cube;
1391     Line **lines;
1392     Polygon *polygons;
1393     Square *squares;
1394     int Nlines;
1395     int Npolygons;
1396     int ambiguous;
1397     int const_i;
1398     double const_value;
1399     int x1,x2,x3;
1400     double *dx;
1401     void split_to_squares();
1402     void check_ambiguous(int);
1403   public:
1404     Cube();
1405     ~Cube();
1406     void init(double***&,int,double,double*&);
1407     void construct_polygons(double);
1408     int get_Nlines();
1409     int get_Npolygons();
1410     int is_ambiguous();
1411     Polygon* get_polygons();
1412 };
1413 
1414 /**
1415  *
1416  * Constructor allocated memory.
1417  *
1418  */
1419 Cube::Cube()
1420 {
1421   cube = new double**[STEPS];
1422   for (int i=0; i < STEPS; i++) {
1423     cube[i] = new double*[STEPS];
1424     for (int j=0; j < STEPS; j++) {
1425       cube[i][j] = new double[STEPS];
1426     }
1427   }
1428   lines = new Line*[NSQUARES*2]; //Each square may have max. 2 lines
1429   polygons = new Polygon[MAX_POLY];
1430   squares = new Square[NSQUARES];
1431 }
1432 
1433 /**
1434  *
1435  * Destructor frees memory allocated in constructor.
1436  *
1437  */
1438 Cube::~Cube()
1439 {
1440   for (int i=0; i < STEPS; i++) {
1441     for (int j=0; j < STEPS; j++) {
1442       delete[] cube[i][j];
1443     }
1444     delete[] cube[i];
1445   }
1446   delete[] cube;
1447   delete[] lines;
1448   delete[] polygons;
1449   delete[] squares;
1450 }
1451 
1452 /**
1453  *
1454  * Initializes the cube. Can be used several times to replace the old cube
1455  * wit a new one.
1456  *
1457  * @param [in] c     Values at the corners of cube
1458  * @param [in] c_i   Index that is constant at this square
1459  * @param [in] c_val Value for the constant index
1460  * @param [in] dex   Lenghts of the sides
1461  *
1462  */
1463 void Cube::init(double ***&c, int c_i, double c_v, double *&dex)
1464 {
1465   const_i = c_i;
1466   const_value = c_v;
1467   dx = dex;
1468   //Here we fix the non-zero indices
1469   x1 = -1;
1470   x2 = -1;
1471   x3 = -1;
1472   for (int i=0; i < DIM; i++) {
1473     if ( i != c_i ) {
1474       if ( x1 < 0 ) {
1475         x1 = i;
1476       } else if ( x2 < 0 ) {
1477         x2 = i;
1478       } else {
1479         x3 = i;
1480       }
1481     }
1482   }
1483   for (int i=0; i < STEPS; i++) {
1484     for (int j=0; j < STEPS; j++) {
1485       for (int k=0; k < STEPS; k++) {
1486         cube[i][j][k] = c[i][j][k];
1487       }
1488     }
1489   }
1490   //We need to set these to zero so when this function is called
1491   //again we know that nothing has been done for this cube
1492   Nlines = 0;
1493   Npolygons = 0;
1494   ambiguous = 0;
1495 }
1496 
1497 /**
1498  *
1499  * Splits given cube to squares.
1500  *
1501  */
1502 void Cube::split_to_squares()
1503 {
1504   double **sq = new double*[STEPS];
1505   int *c_i = new int[STEPS];
1506   double *c_v = new double[STEPS];
1507   for (int i=0; i < STEPS; i++) {
1508     sq[i] = new double[STEPS]; 
1509   }
1510   int Nsquares = 0;
1511   for (int i=0; i < DIM; i++) {
1512     //i is the index which is kept constant, thus we ignore the index which
1513     //is constant in this cube
1514     if ( i != const_i ) {
1515       c_i[0] = const_i;
1516       c_i[1] = i;
1517       for (int j=0; j < STEPS; j++) {
1518         c_v[0] = const_value;
1519         c_v[1] = j*dx[i];
1520         for (int ci1=0; ci1 < STEPS; ci1++) {
1521           for (int ci2=0; ci2 < STEPS; ci2++) {
1522             if ( i == x1 ) {
1523               sq[ci1][ci2] = cube[j][ci1][ci2];
1524             } else if ( i == x2 ) {
1525               sq[ci1][ci2] = cube[ci1][j][ci2];
1526             } else {
1527               sq[ci1][ci2] = cube[ci1][ci2][j];
1528             }
1529           }
1530         }
1531         squares[Nsquares].init(sq,c_i,c_v,dx);
1532         Nsquares++;
1533       }
1534     }
1535   }
1536   for (int i=0; i < STEPS; i++) {
1537     delete[] sq[i];
1538   }
1539   delete[] sq; 
1540   delete[] c_i;
1541   delete[] c_v;
1542 }
1543 
1544 /**
1545  *
1546  * Here we construct polygons from the lines. If the surface cannot be
1547  * ambiguous, all lines are just added to single polygon, but if the
1548  * surface might be ambiguous we order the lines and determine how many
1549  * polygons we have.
1550  *
1551  */
1552 void Cube::construct_polygons(double value0)
1553 {
1554   //Let's start by splitting the cube to squares and finding
1555   //the lines from them
1556   split_to_squares();
1557   for (int i=0; i < NSQUARES; i++) {
1558     squares[i].construct_lines(value0);
1559   } 
1560   //Then we make a table which contains pointers to the lines
1561   Nlines = 0;
1562   for (int i=0; i < NSQUARES; i++) {
1563     int Nline = squares[i].get_Nlines();
1564     Line *l = squares[i].get_lines();
1565     for (int j=0; j < Nline; j++) {
1566       lines[Nlines] = &l[j];
1567       double *p = lines[Nlines]->get_start();
1568       p = lines[Nlines]->get_end();
1569       Nlines++; 
1570     }
1571     l = NULL;
1572   }
1573   //If no lines were found we may exit. This can happen only in 4D case
1574   if ( Nlines == 0 ) {
1575     return;
1576   }
1577   //Then we check if the surface is ambiguous and continue accordingly
1578   check_ambiguous(Nlines);
1579   if ( ambiguous > 0 ) {
1580     //Surface is ambiguous, so let's connect the lines to polygons and see how
1581     //many polygons we have
1582     int *not_used = new int[Nlines];
1583     for (int i=0; i < Nlines; i++) {
1584       not_used[i] = 1;
1585     }
1586     int used = 0; //this keeps track how many lines we have used
1587     //We may found several polygons with this
1588     do {
1589       if ( Nlines - used < 3 ) {
1590         cout << "Error: cannot construct polygon from " << Nlines -used << " lines" << endl;
1591         exit(1);
1592       }
1593       //First we initialize polygon
1594       polygons[Npolygons].init(const_i);
1595       //Then we go through all lines and try to add them to polygon
1596       for (int i=0; i < Nlines; i++) {
1597         if ( not_used[i] ) {
1598           //add_line returns true if line is succesfully added
1599           if ( polygons[Npolygons].add_line(lines[i],0) ) {
1600             not_used[i]=0;
1601             used++;
1602             //if line is succesfully added we start the loop from the
1603             //beginning
1604             i=0;
1605           }
1606         }
1607       }
1608       //When we have reached this point one complete polygon is formed
1609       Npolygons++;
1610     } while ( used < Nlines );
1611     delete[] not_used;
1612   } else {
1613     //Surface is not ambiguous, so we have only one polygons and all lines
1614     //can be added to it without ordering them
1615     polygons[Npolygons].init(const_i);
1616     for (int i=0; i < Nlines; i++) {
1617       polygons[Npolygons].add_line(lines[i],1);
1618     }
1619     Npolygons++;
1620   }
1621 }
1622 
1623 /**
1624  *
1625  * Checks if the surface is ambiguous in this cube.
1626  *
1627  */
1628 void Cube::check_ambiguous(int Nlines)
1629 {
1630   //First we check if any squares may have ambiguous elements
1631   for (int i=0; i < NSQUARES; i++) {
1632     if ( squares[i].is_ambiguous() ) {
1633       ambiguous++;
1634     }
1635   }
1636   //If the surface is not ambigous already, it is still possible to
1637   //have a ambiguous case if we have exatcly 6 lines, i.e. the surface
1638   //elements are at the opposite corners
1639   if ( ambiguous == 0 && Nlines == 6 ) {
1640     ambiguous++;
1641   }
1642 }
1643 
1644 /**
1645  *
1646  * Tells if the surface elements is ambiguous in this cube. Zero if not
1647  * ambiguous, non-zero if ambiguous.
1648  *
1649  * @return Zero if not ambiguous, non-zero if ambiguous
1650  *
1651  */
1652 int Cube::is_ambiguous()
1653 {
1654   return ambiguous;
1655 }
1656 
1657 /**
1658  *
1659  * Returns the number of the lines in this cube.
1660  *
1661  * @return Number of the lines
1662  *
1663  */
1664 int Cube::get_Nlines()
1665 {
1666   return Nlines;
1667 }
1668 
1669 /**
1670  *
1671  * Returns the number of the polygons in this cube.
1672  * 
1673  * @return Number of the polygons in this cube
1674  *
1675  */
1676 int Cube::get_Npolygons()
1677 {
1678   return Npolygons;
1679 }
1680 
1681 /**
1682  *
1683  * Returns a table containing the polygons found from this cube.
1684  *
1685  * @return List of the polygons found from this cube
1686  *
1687  */
1688 Polygon* Cube::get_polygons()
1689 {
1690   return polygons;
1691 }
1692 
1693 /**
1694  *
1695  * This class handles 4d-cubes. Splits them into cubes and collects the
1696  * polygons from the cubes and form polyhedrons from these. 
1697  *
1698  */
1699 class Hypercube
1700 {
1701   private:
1702     static const int DIM = 4;
1703     static const int MAX_POLY = 10;
1704     static const int NCUBES = 8;
1705     static const int STEPS = 2;
1706     double ****hcube;
1707     Polyhedron *polyhedrons;
1708     Polygon **polygons;
1709     Cube *cubes;
1710     int Npolyhedrons;
1711     int ambiguous;
1712     int x1,x2,x3,x4;
1713     double *dx;
1714     void split_to_cubes();
1715     void check_ambiguous(double);
1716   public:
1717     Hypercube();
1718     ~Hypercube();
1719     void init(double****,double*);
1720     void construct_polyhedrons(double);
1721     int get_Npolyhedrons();
1722     Polyhedron* get_polyhedrons();
1723 };
1724 
1725 /**
1726  *
1727  * Constructor allocates memory.
1728  *
1729  */
1730 Hypercube::Hypercube()
1731 {
1732   hcube = new double***[STEPS];
1733   for (int i=0; i < STEPS; i++) {
1734     hcube[i] = new double**[STEPS];
1735     for (int j=0; j < STEPS; j++) {
1736       hcube[i][j] = new double*[STEPS];
1737       for (int k=0; k < STEPS; k++) {
1738         hcube[i][j][k] = new double[STEPS];
1739       }
1740     }
1741   }
1742   polyhedrons = new Polyhedron[MAX_POLY];
1743   polygons = new Polygon*[NCUBES*10];
1744   cubes = new Cube[NCUBES];
1745 }
1746 
1747 /**
1748  *
1749  * Destructor frees memory allocated in the constructor.
1750  *
1751  */
1752 Hypercube::~Hypercube()
1753 {
1754   for (int i=0; i < STEPS; i++) {
1755     for (int j=0; j < STEPS; j++) {
1756       for (int k=0; k < STEPS; k++) {
1757         delete[] hcube[i][j][k];
1758       }
1759       delete[] hcube[i][j];
1760     }
1761     delete[] hcube[i];
1762   }
1763   delete[] hcube;
1764   delete[] polyhedrons;
1765   delete[] polygons;
1766   delete[] cubes;
1767 }
1768 
1769 /**
1770  *
1771  * Initialized the hypercube. Can be used several times to replace the old
1772  * hypercube with a new one
1773  *
1774  * @param [in] c     Values at the corners of cube
1775  * @param [in] dex   Lenghts of the sides
1776  *
1777  */
1778 void Hypercube::init(double ****c, double *dex)
1779 {
1780   dx = dex;
1781   //Here we fix the non-zero indices
1782   x1 = 0;
1783   x2 = 1;
1784   x3 = 2;
1785   x4 = 3;
1786   for (int i=0; i < STEPS; i++) {
1787     for (int j=0; j < STEPS; j++) {
1788       for (int k=0; k < STEPS; k++) {
1789         for (int l=0; l < STEPS; l++) {
1790           hcube[i][j][k][l] = c[i][j][k][l];
1791         }
1792       }
1793     }
1794   }
1795   //We need to set these to zero so we can use this function to initialize
1796   //many hypercubes
1797   Npolyhedrons = 0;
1798   ambiguous = 0;
1799 }
1800 
1801 /**
1802  *
1803  * Splits given hypercube to cubes.
1804  *
1805  */
1806 void Hypercube::split_to_cubes()
1807 {
1808   double ***cu = new double**[STEPS];
1809   for (int i=0; i < STEPS; i++) {
1810     cu[i] = new double*[STEPS]; 
1811     for (int j=0; j < STEPS; j++) {
1812       cu[i][j] = new double[STEPS]; 
1813     }
1814   }
1815   int Ncubes = 0;
1816   for (int i=0; i < DIM; i++) {
1817     //i is the index which is kept constant, thus we ignore the index which
1818     //is constant in this cube
1819     int c_i = i;
1820     for (int j=0; j < STEPS; j++) {
1821       double c_v = j*dx[i];
1822       for (int ci1=0; ci1 < STEPS; ci1++) {
1823         for (int ci2=0; ci2 < STEPS; ci2++) {
1824           for (int ci3=0; ci3 < STEPS; ci3++) {
1825             if ( i == x1 ) {
1826               cu[ci1][ci2][ci3] = hcube[j][ci1][ci2][ci3];
1827             } else if ( i == x2 ) {
1828               cu[ci1][ci2][ci3] = hcube[ci1][j][ci2][ci3];
1829             } else if ( i == x3 ) {
1830               cu[ci1][ci2][ci3] = hcube[ci1][ci2][j][ci3];
1831             } else {
1832               cu[ci1][ci2][ci3] = hcube[ci1][ci2][ci3][j];
1833             }
1834           }
1835         }
1836       }
1837       cubes[Ncubes].init(cu,c_i,c_v,dx);
1838       Ncubes++;
1839     }
1840   }
1841   for (int i=0; i < STEPS; i++) {
1842     for (int j=0; j < STEPS; j++) {
1843       delete[] cu[i][j];
1844     }
1845     delete[] cu[i];
1846   }
1847   delete[] cu;
1848 }
1849 
1850 /**
1851  *
1852  * Here we construct polyhedrons from the polygons. First we check if the surface
1853  * is ambiguous and if it is not amibiguous we add all polygons to a single
1854  * polyhedron. If surface is ambiguous we need to connect the polygons one by one
1855  * and see in the end how many polyhedrons we have. 
1856  *
1857  */
1858 void Hypercube::construct_polyhedrons(double value0)
1859 {
1860   split_to_cubes();
1861   for (int i=0; i < NCUBES; i++) {
1862     cubes[i].construct_polygons(value0);
1863   }
1864   int Npolygons = 0;
1865   //then polygons are loaded to table
1866   for (int i=0; i < NCUBES; i++) {
1867     int Npoly = cubes[i].get_Npolygons();
1868     Polygon *p = cubes[i].get_polygons();
1869     for (int j=0; j < Npoly; j++) {
1870       polygons[Npolygons] = &p[j];
1871       Npolygons++; 
1872     }
1873   }
1874   check_ambiguous(value0);
1875   if ( ambiguous > 0 ) {
1876     //Here surface might be ambiguous and we need to connect the polygons and
1877     //see how many polyhedrons we have
1878     int *not_used = new int[Npolygons];
1879     for (int i=0; i < Npolygons; i++) {
1880       not_used[i] = 1;
1881     }
1882     int used = 0; //this keeps track how many lines we have used
1883     //We may found several polyhedrons with this
1884     do {
1885       //First we initialize polyhedron
1886       polyhedrons[Npolyhedrons].init();
1887       //Then we go through all polygons and try to add them to polyhedron
1888       for (int i=0; i < Npolygons; i++) {
1889         if ( not_used[i] ) {
1890           //add_polygon returns true if the polygon is succesfully added
1891           if ( polyhedrons[Npolyhedrons].add_polygon(polygons[i],0) ) {
1892             not_used[i]=0;
1893             used++;
1894             //if polygon is succesfully added we start the loop from the
1895             //beginning
1896             i=0;
1897           }
1898         }
1899       }
1900       //When we have reached this point one complete polyhedron is formed
1901       Npolyhedrons++;
1902     } while ( used < Npolygons );
1903     delete[] not_used;
1904     /*if ( ambiguous == 0 && Npolyhedrons != 1 ) {
1905       cout << "error" << endl;
1906     }*/
1907   } else {
1908     //Here surface cannot be ambiguous and all polygons can be added to
1909     //the polygehdron without ordering them
1910     polyhedrons[Npolyhedrons].init();
1911     for (int i=0; i < Npolygons; i++) {
1912       polyhedrons[Npolyhedrons].add_polygon(polygons[i],1);
1913     }
1914     //When we have reached this point one complete polyhedron is formed
1915     Npolyhedrons++;
1916   }
1917 }
1918 
1919 /**
1920  *
1921  * Checks if the surface is ambiguous in this hypercube.
1922  *
1923  */
1924 void Hypercube::check_ambiguous(double value0)
1925 {
1926   for (int i=0; i < NCUBES; i++) {
1927     if ( cubes[i].is_ambiguous() ) {
1928       ambiguous++;
1929     }
1930   }
1931   if ( ambiguous == 0 ) {
1932     int Nlines = 0;
1933     for (int i=0; i < NCUBES; i++) {
1934       Nlines += cubes[i].get_Nlines();
1935     }
1936     int points = 0;
1937     for (int i1=0; i1 < STEPS; i1++) {
1938       for (int i2=0; i2 < STEPS; i2++) {
1939         for (int i3=0; i3 < STEPS; i3++) {
1940           for (int i4=0; i4 < STEPS; i4++) {
1941             if ( hcube[i1][i2][i3][i4] < value0 ) {
1942               points++;
1943             }
1944           }
1945         }
1946       }
1947     }
1948     if ( points > 8 ) {
1949       points = 16-points;
1950     }
1951     /* these are not needed
1952     if ( Nlines == 42 ) {
1953       //ambiguous++;
1954     } else if ( Nlines == 36 && ( points == 5 || points == 4 ) ) {
1955       //ambiguous++;
1956     } else if ( Nlines == 30 && points == 3 ) {
1957       //ambiguous++;
1958     }*/
1959     if ( Nlines == 24 && points == 2 ) {
1960       ambiguous++;
1961     }
1962   }
1963 }
1964 
1965 /**
1966  *
1967  * Returns the number of polyhedrons in this cube.
1968  * 
1969  * @return Number of polyhedrons in this hypercube
1970  *
1971  */
1972 int Hypercube::get_Npolyhedrons()
1973 {
1974   return Npolyhedrons;
1975 }
1976 
1977 /**
1978  *
1979  * Returns a table containing the polyhedrons found from this square.
1980  *
1981  * @return List of polyhedrons found from hypercube
1982  *
1983  */
1984 Polyhedron* Hypercube::get_polyhedrons()
1985 {
1986   return polyhedrons;
1987 }
1988 
1989 /**
1990  *
1991  * A class for finding a constant value surface from a 2-4 dimensional
1992  * cube. The values at corners and length of the side are needed as
1993  * an input.
1994  *
1995  * Algorithm by Pasi Huovinen. This code is based on the original FORTRAN
1996  * code by Pasi Huovinen.
1997  *
1998  */
1999 class Cornelius
2000 {
2001   private:
2002     static const int STEPS = 2;
2003     static const int DIM = 4;
2004     static const int MAX_ELEMENTS = 10;
2005     int Nelements;
2006     double **normals;
2007     double **centroids;
2008     int cube_dim;
2009     int initialized;
2010     int print_initialized;
2011     double value0;
2012     double *dx;
2013     ofstream output_print;
2014     void surface_3d(double***,double*,int);
2015     Square cu2d;
2016     Cube cu3d;
2017     Hypercube cu4d;
2018   public:
2019     Cornelius();
2020     ~Cornelius();
2021     void init(int,double,double*);
2022     void init_print(string);
2023     void find_surface_2d(double**);
2024     void find_surface_3d(double***);
2025     void find_surface_3d_print(double***,double*);
2026     void find_surface_4d(double****);
2027     int get_Nelements();
2028     double **get_normals();
2029     double **get_centroids();
2030     double **get_normals_4d();
2031     double **get_centroids_4d();
2032     double get_centroid_elem(int,int);
2033     double get_normal_elem(int,int);
2034 };
2035 
2036 /**
2037  *
2038  * Constructor allocates some memory.
2039  *
2040  */
2041 Cornelius::Cornelius()
2042 {
2043   Nelements = 0;
2044   initialized = 0;
2045   print_initialized = 0;
2046   normals = new double*[MAX_ELEMENTS];
2047   centroids = new double*[MAX_ELEMENTS];
2048   for (int i=0; i < MAX_ELEMENTS; i++) {
2049     normals[i] = new double[DIM];
2050     centroids[i] = new double[DIM];
2051   }
2052 }
2053 
2054 /**
2055  *
2056  * Destructor frees memory and closes printing file is necessary.
2057  *
2058  */
2059 Cornelius::~Cornelius()
2060 {
2061   for (int i=0; i < MAX_ELEMENTS; i++) {
2062     delete[] normals[i];
2063     delete[] centroids[i];
2064   }
2065   delete[] normals;
2066   delete[] centroids;
2067   if ( initialized ) {
2068     delete[] dx;
2069   }
2070   //If file for printing was opened we close it here.
2071   if ( print_initialized ) {
2072     output_print.close();
2073   }
2074 }
2075 
2076 /**
2077  *
2078  * Initializes Cornelius. Can be used several times without any problems. This
2079  * might be useful if cube size varies during evolution.
2080  *
2081  * @param [in] d   Dimension of the problem.
2082  * @param [in] v0  Value which defines the surface.
2083  * @param [in] dex Length of the sides of the cube. Must contains as many elements as
2084  *                 the dimension of the problem (dx1,dx2,...).
2085  *
2086  */
2087 void Cornelius::init(int d, double v0, double *dex)
2088 {
2089   cube_dim = d;
2090   value0 = v0;
2091   if ( initialized != 1 ) {
2092     dx = new double[DIM];
2093   }
2094   for (int i=0; i < DIM; i++) {
2095     if ( i < DIM-cube_dim ) {
2096       dx[i] = 1;
2097     } else {
2098       dx[i] = dex[i-(DIM-cube_dim)];
2099     }
2100   }
2101   initialized = 1;
2102 }
2103 
2104 /**
2105  *
2106  * This initializes the printing of the surface elements into file. Final elements
2107  * are not printed with this, but instead this is used to print the triangles,
2108  * which are used to construct the final elements.
2109  *
2110  * @param [in] filename Filename of the file where the information is printed.
2111  *
2112  */
2113 void Cornelius::init_print(string filename)
2114 {
2115   output_print.open(filename.c_str());
2116   print_initialized = 1;
2117 }
2118 
2119 /**
2120  *
2121  * Finds the surface elements in 2-dimensional case.
2122  *
2123  * @param [in] cube Values at the corners of the cube as a 2d table so that value
2124  *                  [0][0] is at (0,0,0) and [1][1] is at (dx1,dx2).
2125  *
2126  */
2127 void Cornelius::find_surface_2d(double **cube)
2128 {
2129   if ( !initialized || cube_dim != 2 ) {
2130     cout << "Cornelius not initialized for 2D case" << endl;
2131     exit(1);
2132   }
2133   int *c_i = new int[cube_dim];
2134   double *c_v = new double[cube_dim];
2135   c_i[0] = 0;
2136   c_i[1] = 1;
2137   c_v[0] = 0;
2138   c_v[1] = 0;
2139   cu2d.init(cube,c_i,c_v,dx);
2140   cu2d.construct_lines(value0);
2141   Nelements = cu2d.get_Nlines();
2142   Line *l = cu2d.get_lines();
2143   for (int i=0; i < Nelements; i++) {
2144     for (int j=0; j < DIM; j++) {
2145       normals[i][j] = l[i].get_normal()[j];
2146       centroids[i][j] = l[i].get_centroid()[j];
2147     }
2148   }
2149   delete[] c_i;
2150   delete[] c_v;
2151 }
2152 
2153 /**
2154  *
2155  * Finds the surface elements in 3-dimensional case.
2156  *
2157  * @param [in] cube Values at the corners of the cube as a 3d table so that value
2158  *                  [0][0][0] is at (0,0,0) and [1][1][1] is at (dx1,dx2,dx3).
2159  *
2160  */
2161 void Cornelius::find_surface_3d(double ***cube)
2162 {
2163   double *pos = NULL;
2164   surface_3d(cube,pos,0);
2165 }
2166 
2167 /**
2168  *
2169  * Finds the surface elements in 3-dimensional case and prints the actual triangles
2170  * which are found by the algorithm.
2171  *
2172  * @param [in] cube Values at the corners of the cube as a 3d table so that value
2173  *                  [0][0][0] is at (0,0,0) and [1][1][1] is at (dx1,dx2,dx3).
2174  * @param [in] pos  Absolute position at the point [0][0][0] in form (0,x1,x2,x3).
2175  *
2176  */
2177 void Cornelius::find_surface_3d_print(double ***cube, double *pos)
2178 {
2179   surface_3d(cube,pos,1);
2180 }
2181 
2182 /**
2183  *
2184  * Finds the surface elements in 3-dimensional case.
2185  *
2186  * @param [in] cube     Values at the corners of the cube as a 3d table so that value
2187  *                      [0][0][0] is at (0,0,0) and [1][1][1] is at (dx1,dx2,dx3).
2188  * @param [in] pos      Absolute position at the point [0][0][0] in form (0,x1,x2,x3).
2189  * @param [in] do_print 1 if triangles are printed, otherwise 0
2190  *
2191  */
2192 void Cornelius::surface_3d(double ***cube, double *pos, int do_print)
2193 {
2194   if ( !initialized || cube_dim != 3 ) {
2195     cout << "Cornelius not initialized for 3D case" << endl;
2196     exit(1);
2197   }
2198   //First we check if the cube actually contains surface elements.
2199   //If all or none of the elements are below the criterion, no surface
2200   //elements exist.
2201   int above = 0;
2202   for (int i=0; i < STEPS; i++) {
2203     for (int j=0; j < STEPS; j++) { 
2204       for (int k=0; k < STEPS; k++) {
2205         if ( cube[i][j][k] >= value0 )
2206           above++;
2207       }
2208     }
2209   }
2210   if ( above == 0 || above == 8 ) {
2211     //No elements in this cube
2212     Nelements = 0;
2213     return;
2214   }
2215   //This cube has surface elements, so let's start by constructing
2216   //the cube.
2217   int c_i = 0;
2218   double c_v = 0;
2219   cu3d.init(cube,c_i,c_v,dx);
2220   //Then we find the elements
2221   cu3d.construct_polygons(value0);
2222   //Now let's get the information about the elements
2223   Nelements = cu3d.get_Npolygons();
2224   Polygon *p = cu3d.get_polygons();
2225   for (int i=0; i < Nelements; i++) {
2226     //Here we always work with 4-dimensions
2227     for (int j=0; j < DIM; j++) {
2228       normals[i][j] = p[i].get_normal()[j];
2229       centroids[i][j] = p[i].get_centroid()[j];
2230     }
2231     //If we want to print the actual triangles, which are found, we must do it here
2232     //before polygons are removed from the memory.
2233     if ( print_initialized && do_print ) {
2234       p[i].print(output_print,pos);
2235     }
2236   }
2237 }
2238 
2239 /**
2240  *
2241  * Finds the surface elements in 4-dimensional case.
2242  *
2243  * @param [in] cube Values at the corners of the cube as a 4d table so that value
2244  *                  [0][0][0][0] is at (0,0,0,0) and [1][1][1][1] is at
2245  *                  (dx1,dx2,dx3,dx4).
2246  *
2247  */
2248 void Cornelius::find_surface_4d(double ****cube)
2249 {
2250   if ( !initialized || cube_dim != 4 ) {
2251     cout << "Cornelius not initialized for 4D case" << endl;
2252     exit(1);
2253   }
2254   //First we check if the cube actually contains surface elements.
2255   //If all or none of the elements are below the criterion, no surface
2256   //elements exist.
2257   int above = 0;
2258   for (int i=0; i < STEPS; i++) {
2259     for (int j=0; j < STEPS; j++) { 
2260       for (int k=0; k < STEPS; k++) {
2261         for (int l=0; l < STEPS; l++) {
2262           if ( cube[i][j][k][l] >= value0 )
2263             above++;
2264         }
2265       }
2266     }
2267   }
2268   if ( above == 0 || above == 16 ) {
2269     //No elements in this cube
2270     Nelements = 0;
2271     return;
2272   }
2273   //This cube has surface elements, so let's start by constructing
2274   //the hypercube.
2275   cu4d.init(cube,dx);
2276   //Then we find the elements
2277   cu4d.construct_polyhedrons(value0);
2278   //Now let's get the information about the elements
2279   Nelements = cu4d.get_Npolyhedrons();
2280   Polyhedron *p = cu4d.get_polyhedrons();
2281   for (int i=0; i < Nelements; i++) {
2282     for (int j=0; j < DIM; j++) {
2283       centroids[i][j] = p[i].get_centroid()[j];
2284       normals[i][j] = p[i].get_normal()[j];
2285     }
2286   }
2287 }
2288 
2289 /**
2290  *
2291  * Returns the number of the surface elements in the given cube.
2292  *
2293  * @return Number of surface elements in the given cube.
2294  *
2295  */
2296 int Cornelius::get_Nelements()
2297 {
2298   return Nelements;
2299 }
2300 
2301 /**
2302  *
2303  * Returns the centroid vectors as a 2d table with the following number of indices
2304  * [number of elements][4]. If the dimension of the problem is smaller than four,
2305  * first (4-dimension) elements are zero. Note that this function allocates memory and
2306  * the user must free it!
2307  *
2308  * @return Table with dimensions [number of elements][4] containing the normal
2309  *         vectors of the surface elements.
2310  *
2311  */
2312 double** Cornelius::get_centroids_4d()
2313 {
2314   double **vect = new double*[Nelements];
2315   for (int i=0; i < Nelements; i++) {
2316     vect[i] = new double[DIM];
2317     for (int j=0; j < DIM; j++) {
2318       vect[i][j] = centroids[i][j];
2319     }
2320   }
2321   return vect;
2322 }
2323 
2324 /**
2325  *
2326  * Returns the normal vectors as a 2d table with the following number of indices
2327  * [number of elements][4]. If the dimension of the problem is smaller than four,
2328  * first (4-dimension) elements are zero. This gives \sigma_\mu without
2329  * factors(sqrt(-g)) from the metric. Note that this function allocates memory and
2330  * the user must free it!
2331  *
2332  * @return Table with dimensions [number of elements][4] containing the normal
2333  *         vectors of the surface elements.
2334  *
2335  */
2336 double** Cornelius::get_normals_4d()
2337 {
2338   double **vect = new double*[Nelements];
2339   for (int i=0; i < Nelements; i++) {
2340     vect[i] = new double[DIM];
2341     for (int j=0; j < DIM; j++) {
2342       vect[i][j] = normals[i][j];
2343     }
2344   }
2345   return vect;
2346 }
2347 
2348 /**
2349  *
2350  * Returns the centroid vectors as a 2d table with the following number of indices
2351  * [number of elements][dimension of the problem]. Note that this function allocates
2352  * memory and the user must free it!
2353  *
2354  * @return Table with dimensions [number of elements][dimensions] containing the centroid
2355  *         vectors of the surface elements.
2356  *
2357  */
2358 double** Cornelius::get_centroids()
2359 {
2360   double **vect = new double*[Nelements];
2361   for (int i=0; i < Nelements; i++) {
2362     vect[i] = new double[cube_dim];
2363     for (int j=0; j < cube_dim; j++) {
2364       vect[i][j] = centroids[i][j+(DIM-cube_dim)];
2365     }
2366   }
2367   return vect;
2368 }
2369 
2370 /**
2371  *
2372  * Returns the normal vectors as a 2d table with the following number of indices
2373  * [number of elements][dimension of the problem]. This gives \sigma_\mu without
2374  * factors(sqrt(-g)) from the metric. Note that this function allocates memory and
2375  * the user must free it!
2376  *
2377  * @return Table with dimensions [number of elements][dimensions] containing the normal
2378  *         vectors of the surface elements.
2379  *
2380  */
2381 double** Cornelius::get_normals()
2382 {
2383   double **vect = new double*[Nelements];
2384   for (int i=0; i < Nelements; i++) {
2385     vect[i] = new double[cube_dim];
2386     for (int j=0; j < cube_dim; j++) {
2387       vect[i][j] = normals[i][j+(DIM-cube_dim)];
2388     }
2389   }
2390   return vect;
2391 }
2392 
2393 /**
2394  *
2395  * Returns an element of the centroid vector.
2396  *
2397  * @param [in] i Number of surface element whose centroid one wants to get. Valid
2398  *               values are [0,number of elements in this cube].
2399  * @param [in] j Index of the element of centroid. Valid values are
2400  *               [0,dimension of the problem].
2401  * @return       Element j of the centroid of the surface element i.
2402  *
2403  */
2404 double Cornelius::get_centroid_elem(int i, int j)
2405 {
2406   if ( i >= Nelements || j >= cube_dim ) {
2407     cout << "Cornelius error: asking for an element which does not exist." << endl;
2408     exit(1);
2409   }
2410   return centroids[i][j+(DIM-cube_dim)];
2411 }
2412 
2413 /**
2414  *
2415  * Returns an element of the normal vector. This gives \sigma_\mu without factors
2416  * (sqrt(-g)) from the metric.
2417  *
2418  * @param [in] i Number of surface element whose normal one wants to get. Valid
2419  *               values are [0,number of elements in this cube].
2420  * @param [in] j Index of the element of centroid. Valid values are
2421  *               [0,dimension of the problem].
2422  * @return       Element j of the normal of the surface element i.
2423  *
2424  */
2425 double Cornelius::get_normal_elem(int i, int j)
2426 {
2427   if ( i >= Nelements || j >= cube_dim ) {
2428     cout << "Cornelius error: asking for an element which does not exist." << endl;
2429     exit(1);
2430   }
2431   return normals[i][j+(DIM-cube_dim)];
2432 }